diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2011-07-26 18:50:29 +0200 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2011-07-26 18:50:29 +0200 |
commit | e0781f0390291e264e6dd9c17beae1342e87f9a2 (patch) | |
tree | aac2f19ab7e527180952db15867d8daaa23c4a91 /src | |
parent | 2fec84314433c2b7152c6c47b1172a621257fe6f (diff) | |
download | weechat-e0781f0390291e264e6dd9c17beae1342e87f9a2.zip |
core: add mouse support (task #5435), free cursor movement, hook_focus, fix bugs with key "^" (bug #32072, bug #21381), fix bugs with bar windows, completion and /buffer
New features and bugs fixed:
- mouse support: new command /mouse, new option weechat.look.mouse, new key context "mouse"
- free movement of cursor: new command /cursor, new key context "cursor"
- new hook_focus (used by cursor and mouse)
- info "cursor_mode"
- bugs fixed with key "^"
- allow plugin name in /buffer name
- fix bugs with bar windows: do not create bar windows for hidden bars
- fix completion bug when two words for completion are equal but with different case
- automatic scroll direction in /bar scroll (x/y is now optional)
Diffstat (limited to 'src')
52 files changed, 3497 insertions, 637 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c index 24c886190..02de535df 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -55,6 +55,7 @@ #include "../gui/gui-buffer.h" #include "../gui/gui-chat.h" #include "../gui/gui-color.h" +#include "../gui/gui-cursor.h" #include "../gui/gui-filter.h" #include "../gui/gui-history.h" #include "../gui/gui-hotlist.h" @@ -62,6 +63,7 @@ #include "../gui/gui-key.h" #include "../gui/gui-layout.h" #include "../gui/gui-main.h" +#include "../gui/gui-mouse.h" #include "../gui/gui-window.h" #include "../plugins/plugin.h" #include "../plugins/plugin-config.h" @@ -499,7 +501,7 @@ COMMAND_CALLBACK(buffer) { struct t_gui_buffer *ptr_buffer, *weechat_buffer; long number, number1, number2; - char *error, *value, *pos, *str_number1, *pos_number2; + char *error, *value, *pos, *str_number1, *pos_number2, *plugin_name; int i, target_buffer; /* make C compiler happy */ @@ -897,7 +899,19 @@ COMMAND_CALLBACK(buffer) else { ptr_buffer = NULL; - ptr_buffer = gui_buffer_search_by_partial_name (NULL, argv_eol[1]); + pos = strchr (argv_eol[1], '.'); + if (pos) + { + plugin_name = string_strndup (argv_eol[1], pos - argv_eol[1]); + if (plugin_name) + { + ptr_buffer = gui_buffer_search_by_partial_name (plugin_name, + pos + 1); + free (plugin_name); + } + } + if (!ptr_buffer) + ptr_buffer = gui_buffer_search_by_partial_name (NULL, argv_eol[1]); if (ptr_buffer) { gui_window_switch_to_buffer (gui_current_window, ptr_buffer, 1); @@ -1099,6 +1113,89 @@ COMMAND_CALLBACK(command) } /* + * command_cursor: free movement of cursor on screen + */ + +COMMAND_CALLBACK(cursor) +{ + char *pos, *str_x, *error; + int x, y; + + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) argv_eol; + + if (argc == 1) + { + gui_cursor_mode_toggle (); + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "go") == 0) + { + if (argc > 2) + { + pos = strchr (argv[2], ','); + if (pos) + { + str_x = string_strndup (argv[2], pos - argv[2]); + pos++; + if (str_x) + { + error = NULL; + x = (int) strtol (str_x, &error, 10); + if (error && !error[0]) + { + error = NULL; + y = (int) strtol (pos, &error, 10); + if (error && !error[0]) + { + gui_cursor_move_xy (x, y); + } + } + } + } + else + gui_cursor_move_area (argv[2]); + } + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "move") == 0) + { + if (argc > 2) + { + if (string_strcasecmp (argv[2], "up") == 0) + gui_cursor_move_add_xy (0, -1); + else if (string_strcasecmp (argv[2], "down") == 0) + gui_cursor_move_add_xy (0, 1); + else if (string_strcasecmp (argv[2], "left") == 0) + gui_cursor_move_add_xy (-1, 0); + else if (string_strcasecmp (argv[2], "right") == 0) + gui_cursor_move_add_xy (1, 0); + else if (string_strcasecmp (argv[2], "area_up") == 0) + gui_cursor_move_area_add_xy (0, -1); + else if (string_strcasecmp (argv[2], "area_down") == 0) + gui_cursor_move_area_add_xy (0, 1); + else if (string_strcasecmp (argv[2], "area_left") == 0) + gui_cursor_move_area_add_xy (-1, 0); + else if (string_strcasecmp (argv[2], "area_right") == 0) + gui_cursor_move_area_add_xy (1, 0); + } + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "stop") == 0) + { + gui_cursor_mode_toggle (); + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_OK; +} + +/* * command_debug: control debug for core/plugins */ @@ -1153,6 +1250,10 @@ COMMAND_CALLBACK(debug) { gui_color_dump (buffer); } + else if (string_strcasecmp (argv[1], "cursor") == 0) + { + gui_cursor_debug_toggle (); + } else if (string_strcasecmp (argv[1], "hdata") == 0) { if ((argc > 2) && (string_strcasecmp (argv[2], "free") == 0)) @@ -1168,6 +1269,10 @@ COMMAND_CALLBACK(debug) { debug_memory (); } + else if (string_strcasecmp (argv[1], "mouse") == 0) + { + gui_mouse_debug_toggle (); + } else if (string_strcasecmp (argv[1], "tags") == 0) { gui_chat_display_tags ^= 1; @@ -2178,9 +2283,9 @@ COMMAND_CALLBACK(input) else if (string_strcasecmp (argv[1], "hotlist_clear") == 0) gui_input_hotlist_clear (buffer); else if (string_strcasecmp (argv[1], "grab_key") == 0) - gui_input_grab_key (buffer); + gui_input_grab_key (buffer, (argc > 2) ? argv[2] : NULL); else if (string_strcasecmp (argv[1], "grab_key_command") == 0) - gui_input_grab_key_command (buffer); + gui_input_grab_key_command (buffer, (argc > 2) ? argv[2] : NULL); else if (string_strcasecmp (argv[1], "scroll_unread") == 0) gui_input_scroll_unread (buffer); else if (string_strcasecmp (argv[1], "set_unread") == 0) @@ -2213,25 +2318,12 @@ void command_key_display (struct t_gui_key *key, struct t_gui_key *default_key) { char *expanded_name; - char str_spaces[20 + 1]; - int length_screen, num_spaces; expanded_name = gui_key_get_expanded_name (key->key); - str_spaces[0] = '\0'; - length_screen = utf8_strlen_screen ((expanded_name) ? - expanded_name : key->key); - num_spaces = 20 - length_screen; - if (num_spaces > 0) - { - memset (str_spaces, ' ', num_spaces); - str_spaces[num_spaces] = '\0'; - } - if (default_key) { - gui_chat_printf (NULL, " %s%s%s => %s%s %s(%s%s %s%s)", - str_spaces, + gui_chat_printf (NULL, " %s%s => %s%s %s(%s%s %s%s)", (expanded_name) ? expanded_name : key->key, GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), GUI_COLOR(GUI_COLOR_CHAT), @@ -2244,8 +2336,7 @@ command_key_display (struct t_gui_key *key, struct t_gui_key *default_key) } else { - gui_chat_printf (NULL, " %s%s%s => %s%s", - str_spaces, + gui_chat_printf (NULL, " %s%s => %s%s", (expanded_name) ? expanded_name : key->key, GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), GUI_COLOR(GUI_COLOR_CHAT), @@ -2311,7 +2402,8 @@ command_key_display_listdiff (int context) { gui_chat_printf (NULL, ""); gui_chat_printf (NULL, - _("Key bindings added or redefined (%d) for " + /* TRANSLATORS: first "%d" is number of keys */ + _("%d key bindings added or redefined for " "context \"%s\":"), count_added, _(gui_key_context_string[context])); @@ -2340,7 +2432,8 @@ command_key_display_listdiff (int context) { gui_chat_printf (NULL, ""); gui_chat_printf (NULL, - _("Key bindings deleted (%d) for context \"%s\":"), + /* TRANSLATORS: first "%d" is number of keys */ + _("%d key bindings deleted for context \"%s\":"), count_deleted, _(gui_key_context_string[context])); for (ptr_default_key = gui_default_keys[context]; ptr_default_key; @@ -2357,6 +2450,7 @@ command_key_display_listdiff (int context) /* display a message if all key bindings are default bindings */ if ((count_added == 0) && (count_deleted == 0)) { + gui_chat_printf (NULL, ""); gui_chat_printf (NULL, _("No key binding added, redefined or removed " "for context \"%s\""), @@ -2480,8 +2574,9 @@ COMMAND_CALLBACK(key) { command_key_display_list (_("No key binding defined for " "context \"%s\""), - _("Key bindings (%d) for " - "context \"%s\":"), + /* TRANSLATORS: first "%d" is number of keys */ + _("%d key bindings for context " + "\"%s\":"), i, gui_keys[i], gui_keys_count[i]); } } @@ -2512,7 +2607,8 @@ COMMAND_CALLBACK(key) { command_key_display_list (_("No default key binding for " "context \"%s\""), - _("Default key bindings (%d) for " + /* TRANSLATORS: first "%d" is number of keys */ + _("%d default key bindings for " "context \"%s\":"), i, gui_default_keys[i], @@ -2940,6 +3036,96 @@ COMMAND_CALLBACK(layout) } /* + * command_mouse_timer_cb: callback for mouse timer + */ + +int +command_mouse_timer_cb (void *data, int remaining_calls) +{ + /* make C compiler happy */ + (void) data; + (void) remaining_calls; + + if (gui_mouse_enabled) + gui_mouse_disable (); + else + gui_mouse_enable (); + + return WEECHAT_RC_OK; +} + +/* + * command_mouse_timer: timer for toggling mouse + */ + +void +command_mouse_timer (const char *delay) +{ + long seconds; + char *error; + + error = NULL; + seconds = strtol (delay, &error, 10); + if (error && !error[0] && (seconds > 0)) + { + hook_timer (NULL, seconds * 1000, 0, 1, &command_mouse_timer_cb, NULL); + } +} + +/* + * command_mouse: mouse control + */ + +COMMAND_CALLBACK(mouse) +{ + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) argv_eol; + + if (argc == 1) + { + gui_mouse_display_state (); + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "enable") == 0) + { + gui_mouse_enable (); + if (argc > 2) + command_mouse_timer (argv[2]); + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "disable") == 0) + { + gui_mouse_disable (); + if (argc > 2) + command_mouse_timer (argv[2]); + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "toggle") == 0) + { + if (gui_mouse_enabled) + gui_mouse_disable (); + else + gui_mouse_enable (); + if (argc > 2) + command_mouse_timer (argv[2]); + return WEECHAT_RC_OK; + } + + if (string_strcasecmp (argv[1], "grab") == 0) + { + gui_mouse_grab_init (); + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_OK; +} + +/* * command_mute: execute a command mute */ @@ -4900,10 +5086,10 @@ command_init () " scroll: scroll bar\n" " buffer: name of buffer to scroll ('*' " "means current buffer, you should use '*' for root bars)\n" - " scroll_value: value for scroll: 'x' or 'y', followed by " - "'+', '-', 'b' (beginning) or 'e' (end), value (for +/-), " - "and optional %% (to scroll by %% of width/height, " - "otherwise value is number of chars)\n\n" + " scroll_value: value for scroll: 'x' or 'y' (optional), " + "followed by '+', '-', 'b' (beginning) or 'e' (end), " + "value (for +/-), and optional % (to scroll by % of " + "width/height, otherwise value is number of chars)\n\n" "Examples:\n" " create a bar with time, buffer number + name, and completion:\n" " /bar add mybar root bottom 1 0 [time],buffer_number+:+buffer_name,completion\n" @@ -5035,12 +5221,37 @@ command_init () "added if not found at beginning of command)"), "%(plugins_names)|" PLUGIN_CORE " %(plugins_commands)", &command_command, NULL); + hook_command (NULL, "cursor", + N_("free movement of cursor on screen to execute actions on " + "specific areas of screen"), + N_("go chat|<bar>|<x>,<y>" + " || move up|down|left|right|area_up|area_down|area_left|" + "area_right" + " || stop"), + N_(" go: move cursor to chat area, a bar (using bar name) " + "or coordinates \"x,y\"\n" + "move: move cursor with direction\n" + "stop: stop cursor mode\n\n" + "Without argument, this command toggles cursor mode.\n\n" + "When mouse is enabled (see /help mouse), by default a " + "middle click will start cursor mode at this point.\n\n" + "Examples:\n" + " go to nicklist:\n" + " /cursor go nicklist\n" + " go to coordinates x=10, y=5:\n" + " /cursor go 10,5"), + "go %(cursor_areas)" + " || move up|down|left|right|area_up|area_down|area_left|" + "area_right" + " || stop", + &command_cursor, NULL); hook_command (NULL, "debug", N_("control debug for core/plugins"), N_("list" " || set <plugin> <level>" " || dump [<plugin>]" - " || buffer|color|infolists|memory|tags|term|windows" + " || buffer|color|cursor|infolists|memory|mouse|tags|" + "term|windows" " || hdata [free]"), N_(" list: list plugins with debug levels\n" " set: set debug level for plugin\n" @@ -5051,10 +5262,12 @@ command_init () " buffer: dump buffer content with hexadecimal values " "in log file\n" " color: display infos about current color pairs\n" + " cursor: toggle debug for cursor mode\n" " hdata: display infos about hdata (with free: remove " "all hdata in memory)\n" "infolists: display infos about infolists\n" " memory: display infos about memory usage\n" + " mouse: toggle debug for mouse\n" " tags: display tags for lines\n" " term: display infos about terminal\n" " windows: display windows tree"), @@ -5063,9 +5276,11 @@ command_init () " || dump %(plugins_names)|core" " || buffer" " || color" + " || cursor" " || hdata free" " || infolists" " || memory" + " || mouse" " || tags" " || term" " || windows", @@ -5208,9 +5423,11 @@ command_init () "visited buffer\n" " jump_next_visited_buffer: jump to next visited buffer\n" " hotlist_clear: clear hotlist\n" - " grab_key: grab a key\n" + " grab_key: grab a key (optional argument: delay for end " + "of grab, default is 500 milliseconds)\n" " grab_key_command: grab a key with its associated " - "command\n" + "command (optional argument: delay for end of grab, " + "default is 500 milliseconds)\n" " scroll_unread: scroll to unread marker\n" " set_unread: set unread marker for all buffers\n" " set_unread_current_buffer: set unread marker for " @@ -5272,6 +5489,14 @@ command_init () "When binding a command to a key, it is recommended to " "use key alt+k (or Esc then k), and then press the key " "to bind: this will insert key code in command line.\n\n" + "For context \"mouse\" (possible in context \"cursor\" " + "too), key has format: \"@area:key\" where area can be:\n" + " *: any area on screen\n" + " chat: chat area\n" + " bar(*): any bar\n" + " bar(xxx): bar \"xxx\"\n" + " item(*): any bar item\n" + " item(xxx): bar item \"xxx\"\n\n" "Examples:\n" " key alt-x to toggle nicklist bar:\n" " /key bind meta-x /bar toggle nicklist\n" @@ -5280,7 +5505,11 @@ command_init () " restore default binding for key alt-r:\n" " /key reset meta-r\n" " key \"tab\" to stop search in buffer:\n" - " /key bindctxt search ctrl-I /input search_stop"), + " /key bindctxt search ctrl-I /input search_stop\n" + " middle button of mouse on a nick to retrieve info on " + "nick:\n" + " /key bindctxt mouse @item(buffer_nicklist):button3 " + "/msg nickserv info ${nick}"), "list %(keys_contexts)" " || listdefault %(keys_contexts)" " || listdiff %(keys_contexts)" @@ -5290,7 +5519,7 @@ command_init () " || unbindctxt %(keys_contexts) %(keys_codes)" " || reset %(keys_codes_for_reset)" " || resetctxt %(keys_contexts) %(keys_codes_for_reset)" - " || resetall" + " || resetall %- %(keys_contexts)" " || missing %(keys_contexts)", &command_key, NULL); hook_command (NULL, "layout", @@ -5307,6 +5536,25 @@ command_init () "Without argument, this command displays saved layout."), "save|apply|reset buffers|windows", &command_layout, NULL); + hook_command (NULL, "mouse", + N_("mouse control"), + N_("enable|disable|toggle [<delay>]"), + N_(" enable: enable mouse\n" + "disable: disable mouse\n" + " toggle: toggle mouse\n" + " delay: delay (in seconds) after which initial mouse " + "state is restored (useful to temporarily disable mouse)\n\n" + "To enable/disable mouse at startup, use:\n" + " /set weechat.look.mouse on/off\n\n" + "Examples:\n" + " enable mouse:\n" + " /mouse enable\n" + " toggle mouse for 5 seconds:\n" + " /mouse toggle 5"), + "enable" + " || disable" + " || toggle", + &command_mouse, NULL); hook_command (NULL, "mute", N_("execute a command silently"), N_("[-current | -buffer <name> | -all] command"), diff --git a/src/core/wee-completion.c b/src/core/wee-completion.c index 49cdf9a91..7879fa4da 100644 --- a/src/core/wee-completion.c +++ b/src/core/wee-completion.c @@ -45,11 +45,13 @@ #include "../plugins/plugin.h" #include "../gui/gui-completion.h" #include "../gui/gui-bar.h" +#include "../gui/gui-bar-window.h" #include "../gui/gui-buffer.h" #include "../gui/gui-color.h" #include "../gui/gui-filter.h" #include "../gui/gui-key.h" #include "../gui/gui-nicklist.h" +#include "../gui/gui-window.h" /* @@ -1226,6 +1228,47 @@ completion_list_add_keys_codes_for_reset_cb (void *data, } /* + * completion_list_add_cursor_areas_cb: add areas for free cursor movement + * ("chat" and bar names) + */ + +int +completion_list_add_cursor_areas_cb (void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_gui_bar_window *ptr_bar_win; + struct t_gui_bar *ptr_bar; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + /* add "chat" for chat area */ + gui_completion_list_add (completion, "chat", 0, WEECHAT_LIST_POS_SORT); + + /* add bar windows (of current window) */ + for (ptr_bar_win = gui_current_window->bar_windows; ptr_bar_win; + ptr_bar_win = ptr_bar_win->next_bar_window) + { + gui_completion_list_add (completion, ptr_bar_win->bar->name, + 0, WEECHAT_LIST_POS_SORT); + } + for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) + { + if (ptr_bar->bar_window) + { + gui_completion_list_add (completion, ptr_bar->name, + 0, WEECHAT_LIST_POS_SORT); + } + } + + return WEECHAT_RC_OK; +} + +/* * completion_init: add hooks for completions done by WeeChat core */ @@ -1311,4 +1354,7 @@ completion_init () N_("key codes that can be reset (keys added, redefined " "or removed)"), &completion_list_add_keys_codes_for_reset_cb, NULL); + hook_completion (NULL, "cursor_areas", + N_("areas (\"chat\" or bar name) for free cursor movement"), + &completion_list_add_cursor_areas_cb, NULL); } diff --git a/src/core/wee-config.c b/src/core/wee-config.c index da8de105b..92e552528 100644 --- a/src/core/wee-config.c +++ b/src/core/wee-config.c @@ -56,6 +56,7 @@ #include "../gui/gui-layout.h" #include "../gui/gui-line.h" #include "../gui/gui-main.h" +#include "../gui/gui-mouse.h" #include "../gui/gui-nicklist.h" #include "../gui/gui-window.h" #include "../plugins/plugin.h" @@ -108,6 +109,7 @@ struct t_config_option *config_look_input_undo_max; struct t_config_option *config_look_item_time_format; struct t_config_option *config_look_jump_current_to_previous_buffer; struct t_config_option *config_look_jump_previous_buffer_when_closing; +struct t_config_option *config_look_mouse; struct t_config_option *config_look_nickmode; struct t_config_option *config_look_nickmode_empty; struct t_config_option *config_look_paste_max_lines; @@ -1794,6 +1796,11 @@ config_weechat_init_options () N_("jump to previously visited buffer when closing a buffer (if " "disabled, then jump to buffer number - 1)"), NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + config_look_mouse = config_file_new_option ( + weechat_config_file, ptr_section, + "mouse", "boolean", + N_("enable mouse support at startup (to enable it now, see /help mouse)"), + NULL, 0, 0, "off", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); config_look_nickmode = config_file_new_option ( weechat_config_file, ptr_section, "nickmode", "boolean", diff --git a/src/core/wee-config.h b/src/core/wee-config.h index c09544a1a..a617e8f98 100644 --- a/src/core/wee-config.h +++ b/src/core/wee-config.h @@ -133,6 +133,7 @@ extern struct t_config_option *config_look_input_undo_max; extern struct t_config_option *config_look_item_time_format; extern struct t_config_option *config_look_jump_current_to_previous_buffer; extern struct t_config_option *config_look_jump_previous_buffer_when_closing; +extern struct t_config_option *config_look_mouse; extern struct t_config_option *config_look_nickmode; extern struct t_config_option *config_look_nickmode_empty; extern struct t_config_option *config_look_paste_max_lines; diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c index 9cb6404a9..89005dea7 100644 --- a/src/core/wee-hook.c +++ b/src/core/wee-hook.c @@ -49,9 +49,13 @@ #include "wee-utf8.h" #include "wee-util.h" #include "../gui/gui-chat.h" +#include "../gui/gui-bar.h" +#include "../gui/gui-bar-window.h" #include "../gui/gui-color.h" #include "../gui/gui-completion.h" +#include "../gui/gui-cursor.h" #include "../gui/gui-line.h" +#include "../gui/gui-window.h" #include "../plugins/plugin.h" @@ -2744,6 +2748,150 @@ hook_hdata_get (struct t_weechat_plugin *plugin, const char *hdata_name) } /* + * hook_focus: hook a focus + */ + +struct t_hook * +hook_focus (struct t_weechat_plugin *plugin, const char *area, + t_hook_callback_focus *callback, void *callback_data) +{ + struct t_hook *new_hook; + struct t_hook_focus *new_hook_focus; + int priority; + const char *ptr_area; + + if (!area || !area[0] || !callback) + return NULL; + + new_hook = malloc (sizeof (*new_hook)); + if (!new_hook) + return NULL; + new_hook_focus = malloc (sizeof (*new_hook_focus)); + if (!new_hook_focus) + { + free (new_hook); + return NULL; + } + + hook_get_priority_and_name (area, &priority, &ptr_area); + hook_init_data (new_hook, plugin, HOOK_TYPE_FOCUS, priority, + callback_data); + + new_hook->hook_data = new_hook_focus; + new_hook_focus->callback = callback; + new_hook_focus->area = strdup ((ptr_area) ? ptr_area : area); + + hook_add_to_list (new_hook); + + return new_hook; +} + +/* + * hook_focus_hashtable_map_cb: add keys of a hashtable into another + */ + +void +hook_focus_hashtable_map_cb (void *data, struct t_hashtable *hashtable, + const void *key, const void *value) +{ + struct t_hashtable *hashtable1; + + /* make C compiler happy */ + (void) hashtable; + + hashtable1 = (struct t_hashtable *)data; + + if (hashtable1 && key && value) + hashtable_set (hashtable1, (const char *)key, (const char *)value); +} + +/* + * hook_focus_get_data: get data for focus on (x,y) on screen + */ + +struct t_hashtable * +hook_focus_get_data (struct t_gui_cursor_info *cursor_info) +{ + struct t_hook *ptr_hook, *next_hook; + struct t_hashtable *hash_info, *hash_info2; + char str_value[64]; + + hook_exec_start (); + + hash_info = hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (!hash_info) + return NULL; + + /* fill hash_info with values from cursor_info */ + snprintf (str_value, sizeof (str_value), "%d", cursor_info->x); + hashtable_set (hash_info, "_x", str_value); + snprintf (str_value, sizeof (str_value), "%d", cursor_info->y); + hashtable_set (hash_info, "_y", str_value); + snprintf (str_value, sizeof (str_value), + "0x%lx", (long unsigned int)cursor_info->window); + hashtable_set (hash_info, "_window", str_value); + snprintf (str_value, sizeof (str_value), + "0x%lx", + (cursor_info->window) ? + (long unsigned int)((cursor_info->window)->buffer) : 0); + hashtable_set (hash_info, "_buffer", str_value); + hashtable_set (hash_info, "_bar_name", + (cursor_info->bar_window) ? + ((cursor_info->bar_window)->bar)->name : NULL); + hashtable_set (hash_info, "_bar_item_name", + cursor_info->bar_item); + snprintf (str_value, sizeof (str_value), + "%d", cursor_info->item_line); + hashtable_set (hash_info, "_item_line", str_value); + snprintf (str_value, sizeof (str_value), + "%d", cursor_info->item_col); + hashtable_set (hash_info, "_item_col", str_value); + + ptr_hook = weechat_hooks[HOOK_TYPE_FOCUS]; + while (ptr_hook) + { + next_hook = ptr_hook->next_hook; + + if (!ptr_hook->deleted + && !ptr_hook->running + && ((cursor_info->chat + && (strcmp (HOOK_FOCUS(ptr_hook, area), "chat") == 0)) + || (cursor_info->bar_item + && (strcmp (HOOK_FOCUS(ptr_hook, area), cursor_info->bar_item) == 0)))) + { + ptr_hook->running = 1; + hash_info2 = (HOOK_FOCUS(ptr_hook, callback)) + (ptr_hook->callback_data, hash_info); + ptr_hook->running = 0; + + if (hash_info2) + { + if (hash_info2 != hash_info) + { + /* + * add keys of hashtable2 into hashtable and destroy + * hashtable2 + */ + hashtable_map (hash_info2, &hook_focus_hashtable_map_cb, + hash_info); + hashtable_free (hash_info2); + } + } + } + + ptr_hook = next_hook; + } + + hook_exec_end (); + + return hash_info; +} + +/* * unhook: unhook something */ @@ -2933,6 +3081,10 @@ unhook (struct t_hook *hook) if (HOOK_HDATA(hook, description)) free (HOOK_HDATA(hook, description)); break; + case HOOK_TYPE_FOCUS: + if (HOOK_FOCUS(hook, area)) + free (HOOK_FOCUS(hook, area)); + break; case HOOK_NUM_TYPES: /* * this constant is used to count types only, @@ -3372,6 +3524,15 @@ hook_add_to_infolist_type (struct t_infolist *infolist, int type, return 0; } break; + case HOOK_TYPE_FOCUS: + if (!ptr_hook->deleted) + { + if (!infolist_new_var_pointer (ptr_item, "callback", HOOK_FOCUS(ptr_hook, callback))) + return 0; + if (!infolist_new_var_string (ptr_item, "area", HOOK_FOCUS(ptr_hook, area))) + return 0; + } + break; case HOOK_NUM_TYPES: /* * this constant is used to count types only, @@ -3671,6 +3832,14 @@ hook_print_log () log_printf (" description . . . . . : '%s'", HOOK_HDATA(ptr_hook, description)); } break; + case HOOK_TYPE_FOCUS: + if (!ptr_hook->deleted) + { + log_printf (" focus data:"); + log_printf (" callback. . . . . . . : 0x%lx", HOOK_FOCUS(ptr_hook, callback)); + log_printf (" area. . . . . . . . . : '%s'", HOOK_FOCUS(ptr_hook, area)); + } + break; case HOOK_NUM_TYPES: /* * this constant is used to count types only, diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h index 054976259..65df6e7d0 100644 --- a/src/core/wee-hook.h +++ b/src/core/wee-hook.h @@ -24,9 +24,12 @@ #include <gnutls/gnutls.h> #endif +struct t_gui_bar; struct t_gui_buffer; struct t_gui_line; struct t_gui_completion; +struct t_gui_cursor_info; +struct t_gui_window; struct t_weelist; struct t_hashtable; struct t_infolist; @@ -51,6 +54,7 @@ enum t_hook_type HOOK_TYPE_INFO_HASHTABLE, /* get some info as hashtable */ HOOK_TYPE_INFOLIST, /* get some info as infolist */ HOOK_TYPE_HDATA, /* get hdata pointer */ + HOOK_TYPE_FOCUS, /* focus event (mouse/key) */ /* number of hook types */ HOOK_NUM_TYPES, }; @@ -91,6 +95,7 @@ enum t_hook_type #define HOOK_INFO_HASHTABLE(hook, var) (((struct t_hook_info_hashtable *)hook->hook_data)->var) #define HOOK_INFOLIST(hook, var) (((struct t_hook_infolist *)hook->hook_data)->var) #define HOOK_HDATA(hook, var) (((struct t_hook_hdata *)hook->hook_data)->var) +#define HOOK_FOCUS(hook, var) (((struct t_hook_focus *)hook->hook_data)->var) struct t_hook { @@ -374,6 +379,17 @@ struct t_hook_hdata char *description; /* description */ }; +/* hook focus */ + +typedef struct t_hashtable *(t_hook_callback_focus)(void *data, + struct t_hashtable *info); + +struct t_hook_focus +{ + t_hook_callback_focus *callback; /* focus callback */ + char *area; /* "chat" or bar item name */ +}; + /* hook variables */ extern struct t_hook *weechat_hooks[]; @@ -521,43 +537,14 @@ extern struct t_hook *hook_hdata (struct t_weechat_plugin *plugin, void *callback_data); extern struct t_hdata *hook_hdata_get (struct t_weechat_plugin *plugin, const char *hdata_name); +extern struct t_hook *hook_focus (struct t_weechat_plugin *plugin, + const char *area, + t_hook_callback_focus *callback, + void *callback_data); +extern struct t_hashtable *hook_focus_get_data (struct t_gui_cursor_info *cursor_info); extern void unhook (struct t_hook *hook); extern void unhook_all_plugin (struct t_weechat_plugin *plugin); extern void unhook_all (); -extern struct t_hdata *hook_hdata_hook_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_command_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_command_run_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_timer_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_fd_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_process_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_connect_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_print_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_signal_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_hsignal_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_config_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_completion_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_modifier_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_info_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_info_hashtable_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_infolist_cb (void *data, - const char *hdata_name); -extern struct t_hdata *hook_hdata_hook_hdata_cb (void *data, - const char *hdata_name); extern int hook_add_to_infolist (struct t_infolist *infolist, const char *arguments); extern void hook_print_log (); diff --git a/src/core/wee-string.c b/src/core/wee-string.c index 1a8dd090f..6d1270221 100644 --- a/src/core/wee-string.c +++ b/src/core/wee-string.c @@ -54,6 +54,7 @@ #include "weechat.h" #include "wee-string.h" #include "wee-config.h" +#include "wee-hashtable.h" #include "wee-utf8.h" #include "../gui/gui-color.h" @@ -1602,3 +1603,89 @@ string_input_for_buffer (const char *string) /* string is a command */ return NULL; } + +/* + * string_replace_with_hashtable: replace ${codes} with value from hashtable + * "errors" is set with number of keys not found + * in hashtable + */ + +char * +string_replace_with_hashtable (const char *string, + struct t_hashtable *hashtable, + int *errors) +{ + int length, length_value, index_string, index_result; + char *result, *key; + const char *pos_end_name, *ptr_value; + + *errors = 0; + + if (!string) + return NULL; + + if (!hashtable) + return strdup (string); + + length = strlen (string) + 1; + result = malloc (length); + if (result) + { + index_string = 0; + index_result = 0; + while (string[index_string]) + { + if ((string[index_string] == '\\') + && (string[index_string + 1] == '$')) + { + index_string++; + result[index_result++] = string[index_string++]; + } + else if ((string[index_string] == '$') + && (string[index_string + 1] == '{')) + { + pos_end_name = strchr (string + index_string + 2, '}'); + if (pos_end_name) + { + key = string_strndup (string + index_string + 2, + pos_end_name - (string + index_string + 2)); + if (key) + { + ptr_value = (const char *)hashtable_get (hashtable, key); + if (ptr_value) + { + length_value = strlen (ptr_value); + length += length_value; + result = realloc (result, length); + if (!result) + { + free (key); + return NULL; + } + strcpy (result + index_result, ptr_value); + index_result += length_value; + index_string += pos_end_name - string - + index_string + 1; + } + else + { + result[index_result++] = string[index_string++]; + (*errors)++; + } + + free (key); + } + else + result[index_result++] = string[index_string++]; + } + else + result[index_result++] = string[index_string++]; + } + else + result[index_result++] = string[index_string++]; + } + result[index_result] = '\0'; + } + + return result; +} diff --git a/src/core/wee-string.h b/src/core/wee-string.h index 8b4465256..48832408f 100644 --- a/src/core/wee-string.h +++ b/src/core/wee-string.h @@ -22,6 +22,8 @@ #include <regex.h> +struct t_hashtable; + extern char *string_strndup (const char *string, int length); extern void string_tolower (char *string); extern void string_toupper (char *string); @@ -66,5 +68,8 @@ extern void string_encode_base64 (const char *from, int length, char *to); extern int string_decode_base64 (const char *from, char *to); extern int string_is_command_char (const char *string); extern const char *string_input_for_buffer (const char *string); +extern char *string_replace_with_hashtable (const char *string, + struct t_hashtable *hashtable, + int *errors); #endif /* __WEECHAT_STRING_H */ diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index ebbfcac48..11c792738 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -24,6 +24,7 @@ gui-bar-window.c gui-bar-window.h gui-buffer.c gui-buffer.h gui-chat.c gui-chat.h gui-color.c gui-color.h +gui-cursor.c gui-cursor.h gui-filter.c gui-filter.h gui-completion.c gui-completion.h gui-history.c gui-history.h @@ -33,6 +34,7 @@ gui-key.c gui-key.h gui-layout.c gui-layout.h gui-line.c gui-line.h gui-main.h +gui-mouse.c gui-mouse.h gui-nicklist.c gui-nicklist.h gui-window.c gui-window.h) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 443bc9968..a53637c35 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -33,6 +33,8 @@ lib_weechat_gui_common_a_SOURCES = gui-bar.c \ gui-chat.h \ gui-color.c \ gui-color.h \ + gui-cursor.c \ + gui-cursor.h \ gui-completion.c \ gui-completion.h \ gui-filter.c \ @@ -50,6 +52,8 @@ lib_weechat_gui_common_a_SOURCES = gui-bar.c \ gui-line.c \ gui-line.h \ gui-main.h \ + gui-mouse.c \ + gui-mouse.h \ gui-nicklist.c \ gui-nicklist.h \ gui-window.c \ diff --git a/src/gui/curses/CMakeLists.txt b/src/gui/curses/CMakeLists.txt index 85007323a..8362df107 100644 --- a/src/gui/curses/CMakeLists.txt +++ b/src/gui/curses/CMakeLists.txt @@ -30,6 +30,7 @@ gui-curses-chat.c gui-curses-color.c gui-curses-key.c gui-curses-main.c +gui-curses-mouse.c gui-curses-term.c gui-curses-window.c) @@ -68,6 +69,8 @@ IF(LIBINTL_LIBRARY) LIST(APPEND EXTRA_LIBS ${LIBINTL_LIBRARY}) ENDIF(LIBINTL_LIBRARY) +LIST(APPEND EXTRA_LIBS "m") + ADD_EXECUTABLE(${EXECUTABLE} ${WEECHAT_CURSES_SRC}) INCLUDE_DIRECTORIES(.. ../../core ../../plugins) diff --git a/src/gui/curses/Makefile.am b/src/gui/curses/Makefile.am index 61ac1f2ec..1bc15cf98 100644 --- a/src/gui/curses/Makefile.am +++ b/src/gui/curses/Makefile.am @@ -30,13 +30,15 @@ weechat_curses_LDADD = ./../../core/lib_weechat_core.a \ $(PLUGINS_LFLAGS) \ $(NCURSES_LFLAGS) \ $(GCRYPT_LFLAGS) \ - $(GNUTLS_LFLAGS) + $(GNUTLS_LFLAGS) \ + -lm weechat_curses_SOURCES = gui-curses-bar-window.c \ gui-curses-chat.c \ gui-curses-color.c \ gui-curses-key.c \ gui-curses-main.c \ + gui-curses-mouse.c \ gui-curses-term.c \ gui-curses-window.c \ gui-curses.h diff --git a/src/gui/curses/gui-curses-bar-window.c b/src/gui/curses/gui-curses-bar-window.c index d96f925fb..ced409c64 100644 --- a/src/gui/curses/gui-curses-bar-window.c +++ b/src/gui/curses/gui-curses-bar-window.c @@ -39,6 +39,7 @@ #include "../gui-bar-window.h" #include "../gui-chat.h" #include "../gui-color.h" +#include "../gui-cursor.h" #include "../gui-window.h" #include "gui-curses.h" @@ -89,6 +90,9 @@ gui_bar_window_objects_free (struct t_gui_bar_window *bar_window) void gui_bar_window_create_win (struct t_gui_bar_window *bar_window) { + if (CONFIG_BOOLEAN(bar_window->bar->options[GUI_BAR_OPTION_HIDDEN])) + return; + if (GUI_BAR_WINDOW_OBJECTS(bar_window)->win_bar) { delwin (GUI_BAR_WINDOW_OBJECTS(bar_window)->win_bar); @@ -152,14 +156,15 @@ gui_bar_window_print_string (struct t_gui_bar_window *bar_window, int *x, int *y, const char *string, int reset_color_before_display, - int hide_chars_if_scrolling) + int hide_chars_if_scrolling, + int *index_item, int *index_subitem, int *index_line) { int x_with_hidden, size_on_screen, low_char, hidden; char utf_char[16], *next_char, *output; if (!string || !string[0]) return 1; - + wmove (GUI_BAR_WINDOW_OBJECTS(bar_window)->win_bar, *y, *x); if (reset_color_before_display) @@ -239,6 +244,40 @@ gui_bar_window_print_string (struct t_gui_bar_window *bar_window, bar_window->cursor_x += bar_window->x; bar_window->cursor_y += bar_window->y; break; + case GUI_COLOR_BAR_START_ITEM: + string += 2; + if (*index_item < 0) + { + *index_item = 0; + *index_subitem = 0; + } + else + { + (*index_subitem)++; + if (*index_subitem >= bar_window->items_subcount[*index_item]) + { + (*index_item)++; + *index_subitem = 0; + } + } + *index_line = 0; + gui_bar_window_coords_add (bar_window, + (*index_item >= bar_window->items_count) ? -1 : *index_item, + (*index_item >= bar_window->items_count) ? -1 : *index_subitem, + *index_line, + *x + bar_window->x, + *y + bar_window->y); + break; + case GUI_COLOR_BAR_START_LINE_ITEM: + string += 2; + (*index_line)++; + gui_bar_window_coords_add (bar_window, + *index_item, + *index_subitem, + *index_line, + *x + bar_window->x, + *y + bar_window->y); + break; default: string++; break; @@ -353,10 +392,11 @@ gui_bar_window_draw (struct t_gui_bar_window *bar_window, int length_screen_before_cursor, length_screen_after_cursor; int diff, max_length, optimal_number_of_lines; int some_data_not_displayed, separator_horizontal, separator_vertical; + int index_item, index_subitem, index_line; if (!gui_init_ok) return; - + if (!str_start_input[0]) { snprintf (str_start_input, sizeof (str_start_input), "%c%c%c", @@ -384,6 +424,12 @@ gui_bar_window_draw (struct t_gui_bar_window *bar_window, bar_window->cursor_x = -1; bar_window->cursor_y = -1; + /* remove coords */ + gui_bar_window_coords_free (bar_window); + index_item = -1; + index_subitem = -1; + index_line = 0; + filling = gui_bar_get_filling (bar_window->bar); content = gui_bar_window_content_get_with_filling (bar_window, window); @@ -547,7 +593,10 @@ gui_bar_window_draw (struct t_gui_bar_window *bar_window, { if (!gui_bar_window_print_string (bar_window, filling, &x, &y, - items[line], 1, 1)) + items[line], 1, 1, + &index_item, + &index_subitem, + &index_line)) { some_data_not_displayed = 1; } @@ -571,7 +620,10 @@ gui_bar_window_draw (struct t_gui_bar_window *bar_window, while (x < bar_window->width) { gui_bar_window_print_string (bar_window, filling, - &x, &y, " ", 0, 0); + &x, &y, " ", 0, 0, + &index_item, + &index_subitem, + &index_line); } } @@ -618,7 +670,7 @@ gui_bar_window_draw (struct t_gui_bar_window *bar_window, CONFIG_COLOR(bar_window->bar->options[GUI_BAR_OPTION_COLOR_FG]), CONFIG_COLOR(bar_window->bar->options[GUI_BAR_OPTION_COLOR_BG])); } - + /* * move cursor if it was asked in an item content (input_text does that * to move cursor in user input text) @@ -632,7 +684,12 @@ gui_bar_window_draw (struct t_gui_bar_window *bar_window, x = bar_window->width - 2; wmove (GUI_BAR_WINDOW_OBJECTS(bar_window)->win_bar, y, x); wrefresh (GUI_BAR_WINDOW_OBJECTS(bar_window)->win_bar); - move (bar_window->cursor_y, bar_window->cursor_x); + if (!gui_cursor_mode) + { + gui_window_cursor_x = bar_window->cursor_x; + gui_window_cursor_y = bar_window->cursor_y; + move (bar_window->cursor_y, bar_window->cursor_x); + } } else wnoutrefresh (GUI_BAR_WINDOW_OBJECTS(bar_window)->win_bar); diff --git a/src/gui/curses/gui-curses-chat.c b/src/gui/curses/gui-curses-chat.c index 6c380f051..b295abe61 100644 --- a/src/gui/curses/gui-curses-chat.c +++ b/src/gui/curses/gui-curses-chat.c @@ -209,6 +209,8 @@ gui_chat_string_next_char (struct t_gui_window *window, case GUI_COLOR_BAR_START_INPUT_CHAR: case GUI_COLOR_BAR_START_INPUT_HIDDEN_CHAR: case GUI_COLOR_BAR_MOVE_CURSOR_CHAR: + case GUI_COLOR_BAR_START_ITEM: + case GUI_COLOR_BAR_START_LINE_ITEM: string++; break; } diff --git a/src/gui/curses/gui-curses-key.c b/src/gui/curses/gui-curses-key.c index 731a66ee5..d1b7c222c 100644 --- a/src/gui/curses/gui-curses-key.c +++ b/src/gui/curses/gui-curses-key.c @@ -40,8 +40,10 @@ #include "../gui-key.h" #include "../gui-buffer.h" #include "../gui-color.h" -#include "../gui-input.h" +#include "../gui-cursor.h" #include "../gui-completion.h" +#include "../gui-input.h" +#include "../gui-mouse.h" #include "../gui-window.h" #include "gui-curses.h" @@ -79,145 +81,193 @@ gui_key_default_bindings (int context) int i; char key_str[32], command[32]; - switch (context) + if (context == GUI_KEY_CONTEXT_DEFAULT) { - case GUI_KEY_CONTEXT_DEFAULT: - BIND(/* RC */ "ctrl-M", "/input return"); - BIND(/* RC */ "ctrl-J", "/input return"); - BIND(/* tab */ "ctrl-I", "/input complete_next"); - BIND(/* s-tab */ "meta2-Z", "/input complete_previous"); - BIND(/* ^R */ "ctrl-R", "/input search_text"); - BIND(/* basckpace */ "ctrl-H", "/input delete_previous_char"); - BIND(/* basckpace */ "ctrl-?", "/input delete_previous_char"); - BIND(/* ^_ */ "ctrl-_", "/input undo"); - BIND(/* m-_ */ "meta-_", "/input redo"); - BIND(/* del */ "meta2-3~", "/input delete_next_char"); - BIND(/* ^D */ "ctrl-D", "/input delete_next_char"); - BIND(/* ^W */ "ctrl-W", "/input delete_previous_word"); - BIND(/* ^X */ "ctrl-X", "/input switch_active_buffer"); - BIND(/* m-d */ "meta-d", "/input delete_next_word"); - BIND(/* ^K */ "ctrl-K", "/input delete_end_of_line"); - BIND(/* m-r */ "meta-r", "/input delete_line"); - BIND(/* ^T */ "ctrl-T", "/input transpose_chars"); - BIND(/* ^U */ "ctrl-U", "/input delete_beginning_of_line"); - BIND(/* ^Y */ "ctrl-Y", "/input clipboard_paste"); - BIND(/* home */ "meta2-1~", "/input move_beginning_of_line"); - BIND(/* home */ "meta2-H", "/input move_beginning_of_line"); - BIND(/* home */ "meta2-7~", "/input move_beginning_of_line"); - BIND(/* home */ "meta-OH", "/input move_beginning_of_line"); - BIND(/* ^A */ "ctrl-A", "/input move_beginning_of_line"); - BIND(/* end */ "meta2-4~", "/input move_end_of_line"); - BIND(/* end */ "meta2-F", "/input move_end_of_line"); - BIND(/* end */ "meta2-8~", "/input move_end_of_line"); - BIND(/* end */ "meta-OF", "/input move_end_of_line"); - BIND(/* ^E */ "ctrl-E", "/input move_end_of_line"); - BIND(/* left */ "meta2-D", "/input move_previous_char"); - BIND(/* ^B */ "ctrl-B", "/input move_previous_char"); - BIND(/* right */ "meta2-C", "/input move_next_char"); - BIND(/* ^F */ "ctrl-F", "/input move_next_char"); - BIND(/* m-b */ "meta-b", "/input move_previous_word"); - BIND(/* ^left */ "meta-Od", "/input move_previous_word"); - BIND(/* ^left */ "meta-OD", "/input move_previous_word"); - BIND(/* m-f */ "meta-f", "/input move_next_word"); - BIND(/* ^right */ "meta-Oc", "/input move_next_word"); - BIND(/* ^right */ "meta-OC", "/input move_next_word"); - BIND(/* up */ "meta2-A", "/input history_previous"); - BIND(/* down */ "meta2-B", "/input history_next"); - BIND(/* ^up */ "meta-Oa", "/input history_global_previous"); - BIND(/* ^up */ "meta-OA", "/input history_global_previous"); - BIND(/* ^up */ "meta2-1;5A", "/input history_global_previous"); - BIND(/* ^down */ "meta-Ob", "/input history_global_next"); - BIND(/* ^down */ "meta-OB", "/input history_global_next"); - BIND(/* ^down */ "meta2-1;5B", "/input history_global_next"); - BIND(/* m-a */ "meta-a", "/input jump_smart"); - BIND(/* m-j,m-l */ "meta-jmeta-l", "/input jump_last_buffer"); - BIND(/* m-j,m-r */ "meta-jmeta-r", "/server raw"); - BIND(/* m-j,m-s */ "meta-jmeta-s", "/server jump"); - BIND(/* m-h */ "meta-h", "/input hotlist_clear"); - BIND(/* m-k */ "meta-k", "/input grab_key_command"); - BIND(/* m-u */ "meta-u", "/input scroll_unread"); - BIND(/* ^S^U */ "ctrl-Sctrl-U", "/input set_unread"); - BIND(/* ^Cb */ "ctrl-Cb", "/input insert \\x02"); - BIND(/* ^Cc */ "ctrl-Cc", "/input insert \\x03"); - BIND(/* ^Ci */ "ctrl-Ci", "/input insert \\x1D"); - BIND(/* ^Co */ "ctrl-Co", "/input insert \\x0F"); - BIND(/* ^Cr */ "ctrl-Cr", "/input insert \\x12"); - BIND(/* ^Cu */ "ctrl-Cu", "/input insert \\x15"); - BIND(/* m-right */ "meta-meta2-C", "/buffer +1"); - BIND(/* m-right */ "meta2-1;3C", "/buffer +1"); - BIND(/* m-down */ "meta-meta2-B", "/buffer +1"); - BIND(/* m-down */ "meta2-1;3B", "/buffer +1"); - BIND(/* F6 */ "meta2-17~", "/buffer +1"); - BIND(/* ^N */ "ctrl-N", "/buffer +1"); - BIND(/* m-left */ "meta-meta2-D", "/buffer -1"); - BIND(/* m-left */ "meta2-1;3D", "/buffer -1"); - BIND(/* m-up */ "meta-meta2-A", "/buffer -1"); - BIND(/* m-up */ "meta2-1;3A", "/buffer -1"); - BIND(/* F5 */ "meta2-15~", "/buffer -1"); - BIND(/* ^P */ "ctrl-P", "/buffer -1"); - BIND(/* pgup */ "meta2-5~", "/window page_up"); - BIND(/* pgup */ "meta2-I", "/window page_up"); - BIND(/* pgdn */ "meta2-6~", "/window page_down"); - BIND(/* pgdn */ "meta2-G", "/window page_down"); - BIND(/* m-pgup */ "meta-meta2-5~", "/window scroll_up"); - BIND(/* m-pgup */ "meta2-5;3~", "/window scroll_up"); - BIND(/* m-pgdn */ "meta-meta2-6~", "/window scroll_down"); - BIND(/* m-pgdn */ "meta2-6;3~", "/window scroll_down"); - BIND(/* m-home */ "meta-meta2-1~", "/window scroll_top"); - BIND(/* m-home */ "meta-meta2-7~", "/window scroll_top"); - BIND(/* m-end */ "meta-meta2-4~", "/window scroll_bottom"); - BIND(/* m-end */ "meta-meta2-8~", "/window scroll_bottom"); - BIND(/* m-n */ "meta-n", "/window scroll_next_highlight"); - BIND(/* m-p */ "meta-p", "/window scroll_previous_highlight"); - BIND(/* F9 */ "meta2-20~", "/bar scroll title * x-50%"); - BIND(/* F10 */ "meta2-21~", "/bar scroll title * x+50%"); - BIND(/* F11 */ "meta2-23~", "/bar scroll nicklist * y-100%"); - BIND(/* F12 */ "meta2-24~", "/bar scroll nicklist * y+100%"); - BIND(/* m-F11 */ "meta-meta2-23~", "/bar scroll nicklist * yb"); - BIND(/* m-F12 */ "meta-meta2-24~", "/bar scroll nicklist * ye"); - BIND(/* ^L */ "ctrl-L", "/window refresh"); - BIND(/* F7 */ "meta2-18~", "/window -1"); - BIND(/* F8 */ "meta2-19~", "/window +1"); - BIND(/* m-w,m-up */ "meta-wmeta-meta2-A", "/window up"); - BIND(/* m-w,m-up */ "meta-wmeta2-1;3A", "/window up"); - BIND(/* m-w,m-down */ "meta-wmeta-meta2-B", "/window down"); - BIND(/* m-w,m-down */ "meta-wmeta2-1;3B", "/window down"); - BIND(/* m-w,m-right */ "meta-wmeta-meta2-C", "/window right"); - BIND(/* m-w,m-right */ "meta-wmeta2-1;3C", "/window right"); - BIND(/* m-w,m-left */ "meta-wmeta-meta2-D", "/window left"); - BIND(/* m-w,m-left */ "meta-wmeta2-1;3D", "/window left"); - BIND(/* m-w,m-b */ "meta-wmeta-b", "/window balance"); - BIND(/* m-w,m-s */ "meta-wmeta-s", "/window swap"); - BIND(/* m-z */ "meta-z", "/window zoom"); - BIND(/* m-= */ "meta-=", "/filter toggle"); - BIND(/* m-0 */ "meta-0", "/buffer *10"); - BIND(/* m-1 */ "meta-1", "/buffer *1"); - BIND(/* m-2 */ "meta-2", "/buffer *2"); - BIND(/* m-3 */ "meta-3", "/buffer *3"); - BIND(/* m-4 */ "meta-4", "/buffer *4"); - BIND(/* m-5 */ "meta-5", "/buffer *5"); - BIND(/* m-6 */ "meta-6", "/buffer *6"); - BIND(/* m-7 */ "meta-7", "/buffer *7"); - BIND(/* m-8 */ "meta-8", "/buffer *8"); - BIND(/* m-9 */ "meta-9", "/buffer *9"); - BIND(/* m-< */ "meta-<", "/input jump_previously_visited_buffer"); - BIND(/* m-> */ "meta->", "/input jump_next_visited_buffer"); - - /* bind meta-j + {01..99} to switch to buffers # > 10 */ - for (i = 1; i < 100; i++) - { - sprintf (key_str, "meta-j%02d", i); - sprintf (command, "/buffer %d", i); - BIND(key_str, command); - } - break; - case GUI_KEY_CONTEXT_SEARCH: - BIND(/* RC */ "ctrl-M", "/input search_stop"); - BIND(/* RC */ "ctrl-J", "/input search_stop"); - BIND(/* ^R */ "ctrl-R", "/input search_switch_case"); - BIND(/* up */ "meta2-A", "/input search_previous"); - BIND(/* down */ "meta2-B", "/input search_next"); - break; + BIND(/* Enter */ "ctrl-M", "/input return"); + BIND(/* Enter */ "ctrl-J", "/input return"); + BIND(/* tab */ "ctrl-I", "/input complete_next"); + BIND(/* s-tab */ "meta2-Z", "/input complete_previous"); + BIND(/* ^R */ "ctrl-R", "/input search_text"); + BIND(/* basckpace */ "ctrl-H", "/input delete_previous_char"); + BIND(/* basckpace */ "ctrl-?", "/input delete_previous_char"); + BIND(/* ^_ */ "ctrl-_", "/input undo"); + BIND(/* m-_ */ "meta-_", "/input redo"); + BIND(/* del */ "meta2-3~", "/input delete_next_char"); + BIND(/* ^D */ "ctrl-D", "/input delete_next_char"); + BIND(/* ^W */ "ctrl-W", "/input delete_previous_word"); + BIND(/* ^X */ "ctrl-X", "/input switch_active_buffer"); + BIND(/* m-d */ "meta-d", "/input delete_next_word"); + BIND(/* ^K */ "ctrl-K", "/input delete_end_of_line"); + BIND(/* m-r */ "meta-r", "/input delete_line"); + BIND(/* ^T */ "ctrl-T", "/input transpose_chars"); + BIND(/* ^U */ "ctrl-U", "/input delete_beginning_of_line"); + BIND(/* ^Y */ "ctrl-Y", "/input clipboard_paste"); + BIND(/* home */ "meta2-1~", "/input move_beginning_of_line"); + BIND(/* home */ "meta2-H", "/input move_beginning_of_line"); + BIND(/* home */ "meta2-7~", "/input move_beginning_of_line"); + BIND(/* home */ "meta-OH", "/input move_beginning_of_line"); + BIND(/* ^A */ "ctrl-A", "/input move_beginning_of_line"); + BIND(/* end */ "meta2-4~", "/input move_end_of_line"); + BIND(/* end */ "meta2-F", "/input move_end_of_line"); + BIND(/* end */ "meta2-8~", "/input move_end_of_line"); + BIND(/* end */ "meta-OF", "/input move_end_of_line"); + BIND(/* ^E */ "ctrl-E", "/input move_end_of_line"); + BIND(/* left */ "meta2-D", "/input move_previous_char"); + BIND(/* ^B */ "ctrl-B", "/input move_previous_char"); + BIND(/* right */ "meta2-C", "/input move_next_char"); + BIND(/* ^F */ "ctrl-F", "/input move_next_char"); + BIND(/* m-b */ "meta-b", "/input move_previous_word"); + BIND(/* ^left */ "meta-Od", "/input move_previous_word"); + BIND(/* ^left */ "meta-OD", "/input move_previous_word"); + BIND(/* m-f */ "meta-f", "/input move_next_word"); + BIND(/* ^right */ "meta-Oc", "/input move_next_word"); + BIND(/* ^right */ "meta-OC", "/input move_next_word"); + BIND(/* up */ "meta2-A", "/input history_previous"); + BIND(/* down */ "meta2-B", "/input history_next"); + BIND(/* ^up */ "meta-Oa", "/input history_global_previous"); + BIND(/* ^up */ "meta-OA", "/input history_global_previous"); + BIND(/* ^up */ "meta2-1;5A", "/input history_global_previous"); + BIND(/* ^down */ "meta-Ob", "/input history_global_next"); + BIND(/* ^down */ "meta-OB", "/input history_global_next"); + BIND(/* ^down */ "meta2-1;5B", "/input history_global_next"); + BIND(/* m-a */ "meta-a", "/input jump_smart"); + BIND(/* m-j,m-l */ "meta-jmeta-l", "/input jump_last_buffer"); + BIND(/* m-j,m-r */ "meta-jmeta-r", "/server raw"); + BIND(/* m-j,m-s */ "meta-jmeta-s", "/server jump"); + BIND(/* m-h */ "meta-h", "/input hotlist_clear"); + BIND(/* m-k */ "meta-k", "/input grab_key_command"); + BIND(/* m-u */ "meta-u", "/input scroll_unread"); + BIND(/* ^S^U */ "ctrl-Sctrl-U", "/input set_unread"); + BIND(/* ^Cb */ "ctrl-Cb", "/input insert \\x02"); + BIND(/* ^Cc */ "ctrl-Cc", "/input insert \\x03"); + BIND(/* ^Ci */ "ctrl-Ci", "/input insert \\x1D"); + BIND(/* ^Co */ "ctrl-Co", "/input insert \\x0F"); + BIND(/* ^Cr */ "ctrl-Cr", "/input insert \\x12"); + BIND(/* ^Cu */ "ctrl-Cu", "/input insert \\x15"); + BIND(/* m-right */ "meta-meta2-C", "/buffer +1"); + BIND(/* m-right */ "meta2-1;3C", "/buffer +1"); + BIND(/* m-down */ "meta-meta2-B", "/buffer +1"); + BIND(/* m-down */ "meta2-1;3B", "/buffer +1"); + BIND(/* F6 */ "meta2-17~", "/buffer +1"); + BIND(/* ^N */ "ctrl-N", "/buffer +1"); + BIND(/* m-left */ "meta-meta2-D", "/buffer -1"); + BIND(/* m-left */ "meta2-1;3D", "/buffer -1"); + BIND(/* m-up */ "meta-meta2-A", "/buffer -1"); + BIND(/* m-up */ "meta2-1;3A", "/buffer -1"); + BIND(/* F5 */ "meta2-15~", "/buffer -1"); + BIND(/* ^P */ "ctrl-P", "/buffer -1"); + BIND(/* pgup */ "meta2-5~", "/window page_up"); + BIND(/* pgup */ "meta2-I", "/window page_up"); + BIND(/* pgdn */ "meta2-6~", "/window page_down"); + BIND(/* pgdn */ "meta2-G", "/window page_down"); + BIND(/* m-pgup */ "meta-meta2-5~", "/window scroll_up"); + BIND(/* m-pgup */ "meta2-5;3~", "/window scroll_up"); + BIND(/* m-pgdn */ "meta-meta2-6~", "/window scroll_down"); + BIND(/* m-pgdn */ "meta2-6;3~", "/window scroll_down"); + BIND(/* m-home */ "meta-meta2-1~", "/window scroll_top"); + BIND(/* m-home */ "meta-meta2-7~", "/window scroll_top"); + BIND(/* m-end */ "meta-meta2-4~", "/window scroll_bottom"); + BIND(/* m-end */ "meta-meta2-8~", "/window scroll_bottom"); + BIND(/* m-n */ "meta-n", "/window scroll_next_highlight"); + BIND(/* m-p */ "meta-p", "/window scroll_previous_highlight"); + BIND(/* F9 */ "meta2-20~", "/bar scroll title * -30%"); + BIND(/* F10 */ "meta2-21~", "/bar scroll title * +30%"); + BIND(/* F11 */ "meta2-23~", "/bar scroll nicklist * -100%"); + BIND(/* F12 */ "meta2-24~", "/bar scroll nicklist * +100%"); + BIND(/* m-F11 */ "meta-meta2-23~", "/bar scroll nicklist * b"); + BIND(/* m-F12 */ "meta-meta2-24~", "/bar scroll nicklist * e"); + BIND(/* ^L */ "ctrl-L", "/window refresh"); + BIND(/* F7 */ "meta2-18~", "/window -1"); + BIND(/* F8 */ "meta2-19~", "/window +1"); + BIND(/* m-w,m-up */ "meta-wmeta-meta2-A", "/window up"); + BIND(/* m-w,m-up */ "meta-wmeta2-1;3A", "/window up"); + BIND(/* m-w,m-down */ "meta-wmeta-meta2-B", "/window down"); + BIND(/* m-w,m-down */ "meta-wmeta2-1;3B", "/window down"); + BIND(/* m-w,m-right */ "meta-wmeta-meta2-C", "/window right"); + BIND(/* m-w,m-right */ "meta-wmeta2-1;3C", "/window right"); + BIND(/* m-w,m-left */ "meta-wmeta-meta2-D", "/window left"); + BIND(/* m-w,m-left */ "meta-wmeta2-1;3D", "/window left"); + BIND(/* m-w,m-b */ "meta-wmeta-b", "/window balance"); + BIND(/* m-w,m-s */ "meta-wmeta-s", "/window swap"); + BIND(/* m-z */ "meta-z", "/window zoom"); + BIND(/* m-= */ "meta-=", "/filter toggle"); + BIND(/* m-0 */ "meta-0", "/buffer *10"); + BIND(/* m-1 */ "meta-1", "/buffer *1"); + BIND(/* m-2 */ "meta-2", "/buffer *2"); + BIND(/* m-3 */ "meta-3", "/buffer *3"); + BIND(/* m-4 */ "meta-4", "/buffer *4"); + BIND(/* m-5 */ "meta-5", "/buffer *5"); + BIND(/* m-6 */ "meta-6", "/buffer *6"); + BIND(/* m-7 */ "meta-7", "/buffer *7"); + BIND(/* m-8 */ "meta-8", "/buffer *8"); + BIND(/* m-9 */ "meta-9", "/buffer *9"); + BIND(/* m-< */ "meta-<", "/input jump_previously_visited_buffer"); + BIND(/* m-> */ "meta->", "/input jump_next_visited_buffer"); + BIND(/* mouse */ "meta2-M", "/mouse grab"); + BIND(/* m-m */ "meta-m", "/mouse toggle"); + + /* bind meta-j + {01..99} to switch to buffers # > 10 */ + for (i = 1; i < 100; i++) + { + sprintf (key_str, "meta-j%02d", i); + sprintf (command, "/buffer %d", i); + BIND(key_str, command); + } + } + else if (context == GUI_KEY_CONTEXT_SEARCH) + { + BIND(/* Enter */ "ctrl-M", "/input search_stop"); + BIND(/* Enter */ "ctrl-J", "/input search_stop"); + BIND(/* ^R */ "ctrl-R", "/input search_switch_case"); + BIND(/* up */ "meta2-A", "/input search_previous"); + BIND(/* down */ "meta2-B", "/input search_next"); + } + else if (context == GUI_KEY_CONTEXT_CURSOR) + { + BIND(/* Enter */ "ctrl-M", "/cursor stop"); + BIND(/* Enter */ "ctrl-J", "/cursor stop"); + BIND(/* up */ "meta2-A", "/cursor move up"); + BIND(/* down */ "meta2-B", "/cursor move down"); + BIND(/* left */ "meta2-D", "/cursor move left"); + BIND(/* right */ "meta2-C", "/cursor move right"); + BIND(/* m-up */ "meta-meta2-A", "/cursor move area_up"); + BIND(/* m-up */ "meta2-1;3A", "/cursor move area_up"); + BIND(/* m-down */ "meta-meta2-B", "/cursor move area_down"); + BIND(/* m-down */ "meta2-1;3B", "/cursor move area_down"); + BIND(/* m-left */ "meta-meta2-D", "/cursor move area_left"); + BIND(/* m-left */ "meta2-1;3D", "/cursor move area_left"); + BIND(/* m-right */ "meta-meta2-C", "/cursor move area_right"); + BIND(/* m-right */ "meta2-1;3C", "/cursor move area_right"); + BIND(/* b */ "@item(buffer_nicklist):b", "/ban ${nick}"); + BIND(/* k */ "@item(buffer_nicklist):k", "/kick ${nick}"); + BIND(/* K */ "@item(buffer_nicklist):K", "/kickban ${nick}"); + BIND(/* q */ "@item(buffer_nicklist):q", "/query ${nick};/cursor stop"); + BIND(/* w */ "@item(buffer_nicklist):w", "/whois ${nick}"); + } + else if (context == GUI_KEY_CONTEXT_MOUSE) + { + /* mouse events on chat area */ + BIND("@chat:button1-gesture-left", "/buffer -1"); + BIND("@chat:button1-gesture-right", "/buffer +1"); + BIND("@chat:button1-gesture-left-long", "/buffer 1"); + BIND("@chat:button1-gesture-right-long", "/input jump_last_buffer"); + BIND("@chat:wheelup", "/window scroll_up"); + BIND("@chat:wheeldown", "/window scroll_down"); + /* mouse events on nicklist */ + BIND("@bar(nicklist):button1-gesture-up", "/bar scroll nicklist * -100%"); + BIND("@bar(nicklist):button1-gesture-down", "/bar scroll nicklist * +100%"); + BIND("@bar(nicklist):button1-gesture-up-long", "/bar scroll nicklist * b"); + BIND("@bar(nicklist):button1-gesture-down-long", "/bar scroll nicklist * e"); + BIND("@item(buffer_nicklist):button1", "/query ${nick}"); + BIND("@item(buffer_nicklist):button2", "/whois ${nick}"); + BIND("@item(buffer_nicklist):button1-gesture-left", "/kick ${nick}"); + BIND("@item(buffer_nicklist):button1-gesture-left-long", "/kickban ${nick}"); + BIND("@item(buffer_nicklist):button2-gesture-left", "/ban ${nick}"); + /* mouse wheel on any bar */ + BIND("@bar(*):wheelup", "/bar scroll ${_bar_name} * -10%"); + BIND("@bar(*):wheeldown", "/bar scroll ${_bar_name} * +10%"); + /* middle click to enable cursor mode at position */ + BIND("@*:button3", "/cursor go ${_x},${_y}"); } } @@ -246,16 +296,22 @@ gui_key_flush () insert_ok = 1; - if (key < 32) + if (gui_mouse_grab) + { + insert_ok = 0; + key_str[0] = (char) key; + key_str[1] = '\0'; + } + else if (key < 32) { insert_ok = 0; - key_str[0] = '^'; + key_str[0] = '\x01'; key_str[1] = (char) key + '@'; key_str[2] = '\0'; } else if (key == 127) { - key_str[0] = '^'; + key_str[0] = '\x01'; key_str[1] = '?'; key_str[2] = '\0'; } @@ -339,12 +395,6 @@ gui_key_flush () } } - if (strcmp (key_str, "^") == 0) - { - key_str[1] = '^'; - key_str[2] = '\0'; - } - hook_signal_send ("key_pressed", WEECHAT_HOOK_SIGNAL_STRING, key_str); @@ -354,11 +404,9 @@ gui_key_flush () else input_old = NULL; - if ((gui_key_pressed (key_str) != 0) && (insert_ok)) + if ((gui_key_pressed (key_str) != 0) && (insert_ok) + && (!gui_cursor_mode)) { - if (strcmp (key_str, "^^") == 0) - key_str[1] = '\0'; - gui_buffer_undo_snap (gui_current_window->buffer); gui_input_insert_string (gui_current_window->buffer, key_str, -1); @@ -405,9 +453,6 @@ gui_key_flush () free (input_old); } - if (gui_key_grab && (gui_key_grab_count > 0)) - gui_key_grab_end (); - gui_key_buffer_reset (); } } diff --git a/src/gui/curses/gui-curses-main.c b/src/gui/curses/gui-curses-main.c index ce95938a1..b95961fc3 100644 --- a/src/gui/curses/gui-curses-main.c +++ b/src/gui/curses/gui-curses-main.c @@ -48,10 +48,12 @@ #include "../gui-buffer.h" #include "../gui-chat.h" #include "../gui-color.h" +#include "../gui-cursor.h" #include "../gui-filter.h" #include "../gui-input.h" #include "../gui-layout.h" #include "../gui-history.h" +#include "../gui-mouse.h" #include "../gui-nicklist.h" #include "../gui-window.h" #include "gui-curses.h" @@ -149,7 +151,7 @@ gui_main_init () /* * create bar windows for root bars (they were read from config, - * but no window was created (GUI was not initialized) + * but no window was created, GUI was not initialized) */ for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) { @@ -166,6 +168,11 @@ gui_main_init () gui_bar_window_create_win (ptr_bar_win); } } + + if (CONFIG_BOOLEAN(config_look_mouse)) + gui_mouse_enable (); + else + gui_mouse_disable (); } /* @@ -277,7 +284,6 @@ gui_main_refreshs () } /* refresh bars if needed */ - for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) { if (ptr_bar->bar_refresh_needed) @@ -285,6 +291,10 @@ gui_main_refreshs () gui_bar_draw (ptr_bar); } } + + /* move cursor (for cursor mode) */ + if (gui_cursor_mode) + gui_window_move_cursor (); } /* @@ -387,6 +397,9 @@ gui_main_end (int clean_exit) gui_main_refreshs (); } + /* disable mouse */ + gui_mouse_disable (); + /* remove bar items and bars */ gui_bar_item_end (); gui_bar_free_all (); diff --git a/src/gui/curses/gui-curses-mouse.c b/src/gui/curses/gui-curses-mouse.c new file mode 100644 index 000000000..7ca78c77b --- /dev/null +++ b/src/gui/curses/gui-curses-mouse.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2011 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * gui-curses-mouse.c: mouse functions for Curses GUI + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "../../core/weechat.h" +#include "../../core/wee-config.h" +#include "../gui-chat.h" +#include "../gui-mouse.h" + + +/* + * gui_mouse_enable: enable mouse + */ + +void +gui_mouse_enable () +{ + gui_mouse_enabled = 1; + fprintf (stderr, "\033[?1005h\033[?1000h\033[?1002h"); +} + +/* + * gui_mouse_disable: disable mouse + */ + +void +gui_mouse_disable () +{ + gui_mouse_enabled = 0; + fprintf (stderr, "\033[?1002l\033[?1000l\033[?1005l"); +} + +/* + * gui_mouse_display_state: display state of mouse + */ + +void +gui_mouse_display_state () +{ + gui_chat_printf (NULL, + (CONFIG_BOOLEAN(config_look_mouse)) ? + _("Mouse is enabled") : _("Mouse is disabled")); +} + +/* + * gui_mouse_grab_init: init "grab mouse" mode + */ + +void +gui_mouse_grab_init () +{ + gui_mouse_grab = 1; +} + +/* + * gui_mouse_grab_code2key: get key name with a mouse code + */ + +const char * +gui_mouse_grab_code2key (const char *code) +{ + int x, y; + double diff_x, diff_y, distance, angle, pi4; + static char key[128]; + char button[2]; + + /* mouse code must have at least 3 chars */ + if (strlen (code) < 3) + return NULL; + + key[0] = '\0'; + + /* ignore code '#' (button released) if it's received as first event */ + if ((gui_mouse_event_index == 0) && (code[0] == '#')) + return key; + + /* get coordinates and button */ + x = ((unsigned char)code[1]) - 33; + if (x < 0) + x = 0; + y = ((unsigned char)code[2]) - 33; + if (y < 0) + y = 0; + gui_mouse_event_x[gui_mouse_event_index] = x; + gui_mouse_event_y[gui_mouse_event_index] = y; + if (gui_mouse_event_index == 0) + gui_mouse_event_button = code[0]; + + if (gui_mouse_event_index == 0) + gui_mouse_event_index = 1; + + if (code[0] == '`') + { + strcat (key, "wheelup"); + return key; + } + + if (code[0] == 'a') + { + strcat (key, "wheeldown"); + return key; + } + + if (code[0] != '#') + return key; + + /* add button/wheel */ + switch (gui_mouse_event_button) + { + case ' ': /* left button pressed */ + strcat (key, "button1"); + break; + case '"': /* right button pressed */ + strcat (key, "button2"); + break; + case '!': /* middle button pressed */ + strcat (key, "button3"); + break; + default: /* extra buttons: button4..button9 */ + if ((gui_mouse_event_button >= 'b') + && (gui_mouse_event_button <= 'g')) + { + button[0] = gui_mouse_event_button - ('b' - '4'); + button[1] = '\0'; + strcat (key, "button"); + strcat (key, button); + } + break; + } + + /* + * Mouse gesture: if (x,y) on release is different from (x,y) on click, + * compute distance and angle between 2 points. + * + * Distance: sqrt((x2-x1)²+(y2-y1)²) + * Angle : atan2(x1-x1, y2-y1) + * + * Angle: + * + * 3.14 pi + * /\ + * -2.35 || 2.35 3/4 * pi + * || + * -1.57 /----++----\ 1.57 1/2 * pi + * \----++----/ + * || + * -0.78 || 0.78 1/4 * pi + * \/ + * 0.00 0 + * + * Possible returned gestures are: + * + * key name | dist. | angle + * ---------------------------+-------+-------------------------- + * buttonX-gesture-up | 3..19 | -2.35..-3.14 + 2.35..3.14 + * buttonX-gesture-up-long | >= 20 | + * buttonX-gesture-down | 3..19 | -0.78..0.78 + * buttonX-gesture-down-long | >= 20 | + * buttonX-gesture-left | 3..39 | -0.78..-2.35 + * buttonX-gesture-left-long | >= 40 | + * buttonX-gesture-right | 3..39 | 0.78..2.35 + * buttonX-gesture-right-long | >= 40 | + */ + + distance = 0; + if (key[0] + && ((gui_mouse_event_x[0] != gui_mouse_event_x[1]) + || (gui_mouse_event_y[0] != gui_mouse_event_y[1]))) + { + diff_x = gui_mouse_event_x[1] - gui_mouse_event_x[0]; + diff_y = gui_mouse_event_y[1] - gui_mouse_event_y[0]; + distance = sqrt ((diff_x * diff_x) + (diff_y * diff_y)); + if (distance >= 3) + { + angle = atan2 ((double)(gui_mouse_event_x[1] - gui_mouse_event_x[0]), + (double)(gui_mouse_event_y[1] - gui_mouse_event_y[0])); + pi4 = 3.14159265358979 / 4; + if ((angle <= pi4 * (-3)) || (angle >= pi4 * 3)) + { + strcat (key, "-gesture-up"); + if (distance >= 20) + strcat (key, "-long"); + } + else if ((angle >= pi4 * (-1)) && (angle <= pi4)) + { + strcat (key, "-gesture-down"); + if (distance >= 20) + strcat (key, "-long"); + } + else if ((angle >= pi4 * (-3)) && (angle <= pi4 * (-1))) + { + strcat (key, "-gesture-left"); + if (distance >= 40) + strcat (key, "-long"); + } + else if ((angle >= pi4) && (angle <= pi4 * 3)) + { + strcat (key, "-gesture-right"); + if (distance >= 40) + strcat (key, "-long"); + } + } + } + + return key; +} + +/* + * gui_mouse_grab_end: end "grab mouse" mode + */ + +void +gui_mouse_grab_end () +{ + gui_mouse_grab = 0; +} diff --git a/src/gui/curses/gui-curses-window.c b/src/gui/curses/gui-curses-window.c index 3e2f0d90f..bac2ecfd0 100644 --- a/src/gui/curses/gui-curses-window.c +++ b/src/gui/curses/gui-curses-window.c @@ -46,6 +46,7 @@ #include "../gui-buffer.h" #include "../gui-chat.h" #include "../gui-color.h" +#include "../gui-cursor.h" #include "../gui-hotlist.h" #include "../gui-input.h" #include "../gui-key.h" @@ -1514,7 +1515,8 @@ gui_window_refresh_windows () for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) { - if (CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_ROOT) + if ((CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_ROOT) + && !CONFIG_BOOLEAN(ptr_bar->options[GUI_BAR_OPTION_HIDDEN])) { gui_bar_window_calculate_pos_size (ptr_bar->bar_window, NULL); gui_bar_window_create_win (ptr_bar->bar_window); @@ -2197,6 +2199,20 @@ gui_window_set_title (const char *title) } /* + * gui_window_move_cursor: move cursor on screen (for cursor mode) + */ + +void +gui_window_move_cursor () +{ + if (gui_cursor_mode) + { + move (gui_cursor_y, gui_cursor_x); + refresh (); + } +} + +/* * gui_window_term_display_infos: display some infos about terminal and colors */ diff --git a/src/gui/gtk/CMakeLists.txt b/src/gui/gtk/CMakeLists.txt index d40e6b6f6..e6596205d 100644 --- a/src/gui/gtk/CMakeLists.txt +++ b/src/gui/gtk/CMakeLists.txt @@ -25,6 +25,7 @@ gui-gtk-chat.c gui-gtk-color.c gui-gtk-key.c gui-gtk-main.c +gui-gtk-mouse.c gui-gtk-term.c gui-gtk-window.c) diff --git a/src/gui/gtk/Makefile.am b/src/gui/gtk/Makefile.am index 6f84e647f..01833e78d 100644 --- a/src/gui/gtk/Makefile.am +++ b/src/gui/gtk/Makefile.am @@ -37,6 +37,7 @@ weechat_gtk_SOURCES = gui-gtk-bar-window.c \ gui-gtk-color.c \ gui-gtk-key.c \ gui-gtk-main.c \ + gui-gtk-mouse.c \ gui-gtk-term.c \ gui-gtk-window.c \ gui-gtk.h diff --git a/src/gui/gtk/gui-gtk-mouse.c b/src/gui/gtk/gui-gtk-mouse.c new file mode 100644 index 000000000..8d7533d8d --- /dev/null +++ b/src/gui/gtk/gui-gtk-mouse.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * gui-gtk-mouse.c: mouse functions for Gtk GUI + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../../core/weechat.h" +#include "../gui-mouse.h" + + +/* + * gui_mouse_enable: enable mouse + */ + +void +gui_mouse_enable () +{ + /* This function does nothing in Gtk GUI */ +} + +/* + * gui_mouse_disable: disable mouse + */ + +void +gui_mouse_disable () +{ + /* This function does nothing in Gtk GUI */ +} + +/* + * gui_mouse_display_state: display state of mouse + */ + +void +gui_mouse_display_state () +{ + /* This function does nothing in Gtk GUI */ +} + +/* + * gui_mouse_grab_init: init "grab mouse" mode + */ + +void +gui_mouse_grab_init () +{ + /* This function does nothing in Gtk GUI */ +} + +/* + * gui_mouse_grab_code2key: get key name with a mouse code + */ + +const char * +gui_mouse_grab_code2key (const char *code) +{ + (void) code; + + /* This function does nothing in Gtk GUI */ + + return NULL; +} + +/* + * gui_mouse_grab_end: end "grab mouse" mode + */ + +void +gui_mouse_grab_end () +{ + /* This function does nothing in Gtk GUI */ +} diff --git a/src/gui/gtk/gui-gtk-window.c b/src/gui/gtk/gui-gtk-window.c index c7bd94041..baa0dd326 100644 --- a/src/gui/gtk/gui-gtk-window.c +++ b/src/gui/gtk/gui-gtk-window.c @@ -849,6 +849,16 @@ gui_window_set_title (const char *title) } /* + * gui_window_move_cursor: move cursor on screen (for cursor mode) + */ + +void +gui_window_move_cursor () +{ + /* TODO: write this function for Gtk */ +} + +/* * gui_window_term_display_infos: display some infos about terminal and colors */ diff --git a/src/gui/gui-bar-item.c b/src/gui/gui-bar-item.c index 8a20a65bc..5a6af8448 100644 --- a/src/gui/gui-bar-item.c +++ b/src/gui/gui-bar-item.c @@ -47,6 +47,7 @@ #include "gui-chat.h" #include "gui-color.h" #include "gui-completion.h" +#include "gui-cursor.h" #include "gui-filter.h" #include "gui-hotlist.h" #include "gui-key.h" @@ -131,70 +132,6 @@ gui_bar_item_search (const char *item_name) } /* - * gui_bar_item_valid_char_name: return 1 if char is valid for item name - * (any letter, digit, "-" or "_") - * return 0 otherwise - */ - -int -gui_bar_item_valid_char_name (char c) -{ - return (((c >= 'a') && (c <= 'z')) - || ((c >= 'A') && (c <= 'Z')) - || ((c >= '0') && (c <= '9')) - || (c == '-') - || (c == '_')) ? - 1 : 0; -} - -/* - * gui_bar_item_string_get_item_start: return pointer to beginning of item name - * (string may contain special delimiters - * at beginning, which are ignored) - */ - -const char * -gui_bar_item_string_get_item_start (const char *string) -{ - while (string && string[0]) - { - if (gui_bar_item_valid_char_name (string[0])) - break; - string++; - } - if (string && string[0]) - return string; - - return NULL; -} - -/* - * gui_bar_item_string_is_item: return 1 if string is item (string may contain - * special delimiters at beginning and end of - * string, which are ignored) - */ - -int -gui_bar_item_string_is_item (const char *string, const char *item_name) -{ - const char *item_start; - int length; - - item_start = gui_bar_item_string_get_item_start (string); - if (!item_start) - return 0; - - length = strlen (item_name); - if (strncmp (item_start, item_name, length) == 0) - { - if (!gui_bar_item_valid_char_name (item_start[length])) - return 1; - } - - return 0; -} - -/* * gui_bar_item_search_with_plugin: search a bar item for a plugin * if exact_plugin == 1, then search only for * this plugin, otherwise, if plugin is not @@ -249,7 +186,6 @@ gui_bar_item_used_in_a_bar (const char *item_name, int partial_name) { struct t_gui_bar *ptr_bar; int i, j, length; - const char *ptr_start; length = strlen (item_name); @@ -259,13 +195,14 @@ gui_bar_item_used_in_a_bar (const char *item_name, int partial_name) { for (j = 0; j < ptr_bar->items_subcount[i]; j++) { - ptr_start = gui_bar_item_string_get_item_start (ptr_bar->items_array[i][j]); - if (ptr_start) + if (ptr_bar->items_name[i][j]) { if ((partial_name - && strncmp (ptr_start, item_name, length) == 0) + && strncmp (ptr_bar->items_name[i][j], + item_name, length) == 0) || (!partial_name - && strcmp (ptr_start, item_name) == 0)) + && strcmp (ptr_bar->items_name[i][j], + item_name) == 0)) { return 1; } @@ -279,40 +216,39 @@ gui_bar_item_used_in_a_bar (const char *item_name, int partial_name) } /* - * gui_bar_item_get_value: return value of a bar item - * first look for prefix/suffix in name, then run item - * callback (if found) and concatene strings - * for example: if name == "[time]" - * return: color(delimiter) + "[" + - * (value of item "time") + color(delimiter) + - * "]" + * gui_bar_item_set_prefix_name_suffix: get prefix, name and suffix for an item + * for example, item name "[time]" + * will return: + * prefix: "[" + * name : "time" + * suffix: "]" */ -char * -gui_bar_item_get_value (const char *name, struct t_gui_bar *bar, - struct t_gui_window *window) +void +gui_bar_item_set_prefix_name_suffix (const char *item_name, + char **prefix, char **name, char **suffix) { const char *ptr, *start, *end; - char *prefix, *item_name, *suffix; - char *item_value, delimiter_color[32], bar_color[32]; - char *result, str_attr[8]; - int valid_char, length; - struct t_gui_bar_item *ptr_item; - struct t_weechat_plugin *ptr_plugin; + int valid_char; - if (!name) - return NULL; + *prefix = NULL; + *name = NULL; + *suffix = NULL; + + if (!item_name) + return; start = NULL; end = NULL; - prefix = NULL; - item_name = NULL; - suffix = NULL; - ptr = name; + ptr = item_name; while (ptr[0]) { - valid_char = gui_bar_item_valid_char_name (ptr[0]); + valid_char = (((ptr[0] >= 'a') && (ptr[0] <= 'z')) + || ((ptr[0] >= 'A') && (ptr[0] <= 'Z')) + || ((ptr[0] >= '0') && (ptr[0] <= '9')) + || (ptr[0] == '-') + || (ptr[0] == '_')) ? 1 : 0; if (!start && valid_char) start = ptr; else if (start && !end && !valid_char) @@ -321,56 +257,70 @@ gui_bar_item_get_value (const char *name, struct t_gui_bar *bar, } if (start) { - if (start > name) - prefix = string_strndup (name, start - name); + if (start > item_name) + *prefix = string_strndup (item_name, start - item_name); } else - prefix = strdup (name); + *prefix = strdup (item_name); if (start) { - item_name = (end) ? + *name = (end) ? string_strndup (start, end - start + 1) : strdup (start); } if (end && end[0] && end[1]) - suffix = strdup (end + 1); + *suffix = strdup (end + 1); +} + +/* + * gui_bar_item_get_value: return value of a bar item + * run callback if a name exists, then concatenate + * prefix + return of callback + suffix + * for example: if item == "[time]" + * return: color(delimiter) + "[" + + * (value of item "time") + color(delimiter) + + * "]" + */ + +char * +gui_bar_item_get_value (struct t_gui_bar *bar, struct t_gui_window *window, + int item, int subitem) +{ + char *item_value, delimiter_color[32], bar_color[32]; + char *result, str_attr[8]; + int length; + struct t_gui_bar_item *ptr_item; + struct t_weechat_plugin *ptr_plugin; + + if (!bar->items_array[item][subitem]) + return NULL; item_value = NULL; - if (item_name) + if (bar->items_name[item][subitem]) { ptr_plugin = NULL; if (window && window->buffer) ptr_plugin = window->buffer->plugin; else if (gui_current_window && gui_current_window->buffer) ptr_plugin = gui_current_window->buffer->plugin; - ptr_item = gui_bar_item_search_with_plugin (ptr_plugin, 0, item_name); + ptr_item = gui_bar_item_search_with_plugin (ptr_plugin, 0, + bar->items_name[item][subitem]); if (ptr_item && ptr_item->build_callback) { item_value = (ptr_item->build_callback) (ptr_item->build_callback_data, ptr_item, window); } - if (!item_value || !item_value[0]) - { - if (prefix) - { - free (prefix); - prefix = NULL; - } - if (suffix) - { - free (suffix); - suffix = NULL; - } - } + if (!item_value) + return NULL; } length = 0; - if (prefix) - length += 64 + strlen (prefix) + 1; /* color + prefix + color */ + if (bar->items_prefix[item][subitem]) + length += 64 + strlen (bar->items_prefix[item][subitem]) + 1; /* color + prefix + color */ if (item_value && item_value[0]) - length += strlen (item_value) + 16 + 1; /* length + "move cursor" id */ - if (suffix) - length += 32 + strlen (suffix) + 1; /* color + suffix */ - + length += strlen (item_value) + 1; + if (bar->items_suffix[item][subitem]) + length += 32 + strlen (bar->items_suffix[item][subitem]) + 1; /* color + suffix */ + result = NULL; if (length > 0) { @@ -379,7 +329,8 @@ gui_bar_item_get_value (const char *name, struct t_gui_bar *bar, { delimiter_color[0] = '\0'; bar_color[0] = '\0'; - if (prefix || suffix) + if (bar->items_prefix[item][subitem] + || bar->items_suffix[item][subitem]) { /* color for text in bar */ gui_color_attr_build_string (CONFIG_COLOR(bar->options[GUI_BAR_OPTION_COLOR_FG]), @@ -429,21 +380,15 @@ gui_bar_item_get_value (const char *name, struct t_gui_bar *bar, } snprintf (result, length, "%s%s%s%s%s%s", - (prefix) ? delimiter_color : "", - (prefix) ? prefix : "", - (prefix) ? bar_color : "", + (bar->items_prefix[item][subitem]) ? delimiter_color : "", + (bar->items_prefix[item][subitem]) ? bar->items_prefix[item][subitem] : "", + (bar->items_prefix[item][subitem]) ? bar_color : "", (item_value) ? item_value : "", - (suffix) ? delimiter_color : "", - (suffix) ? suffix : ""); + (bar->items_suffix[item][subitem]) ? delimiter_color : "", + (bar->items_suffix[item][subitem]) ? bar->items_suffix[item][subitem] : ""); } } - if (prefix) - free (prefix); - if (item_name) - free (item_name); - if (suffix) - free (suffix); if (item_value) free (item_value); @@ -451,6 +396,30 @@ gui_bar_item_get_value (const char *name, struct t_gui_bar *bar, } /* + * gui_bar_item_count_lines: count number of lines in item + */ + +int +gui_bar_item_count_lines (char *string) +{ + int count, i; + + if (!string || !string[0]) + return 0; + + count = 1; + i = 0; + while (string[i]) + { + if ((string[i] == '\n') && string[i + 1]) + count++; + i++; + } + + return count; +} + +/* * gui_bar_item_new: create a new bar item */ @@ -505,22 +474,20 @@ gui_bar_item_update (const char *item_name) struct t_gui_bar *ptr_bar; struct t_gui_window *ptr_window; struct t_gui_bar_window *ptr_bar_window; - int index_item, index_subitem; + int i, j; for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) { - for (index_item = 0; index_item < ptr_bar->items_count; index_item++) + for (i = 0; i < ptr_bar->items_count; i++) { - for (index_subitem = 0; - index_subitem < ptr_bar->items_subcount[index_item]; - index_subitem++) + for (j = 0; j < ptr_bar->items_subcount[i]; j++) { - if (gui_bar_item_string_is_item (ptr_bar->items_array[index_item][index_subitem], - item_name)) + if (ptr_bar->items_name[i][j] + && (strcmp (ptr_bar->items_name[i][j], item_name) == 0)) { if (ptr_bar->bar_window) { - ptr_bar->bar_window->items_refresh_needed[index_item][index_subitem] = 1; + ptr_bar->bar_window->items_refresh_needed[i][j] = 1; } else { @@ -533,7 +500,7 @@ gui_bar_item_update (const char *item_name) { if (ptr_bar_window->bar == ptr_bar) { - ptr_bar_window->items_refresh_needed[index_item][index_subitem] = 1; + ptr_bar_window->items_refresh_needed[i][j] = 1; } } } @@ -744,11 +711,15 @@ gui_bar_item_default_input_text (void *data, struct t_gui_bar_item *item, "0x%lx", (long unsigned int)(window->buffer)); /* execute modifier with basic string (without cursor tag) */ - ptr_input = hook_modifier_exec (NULL, - "input_text_display", - str_buffer, - (window->buffer->input_buffer) ? - window->buffer->input_buffer : ""); + ptr_input = NULL; + if (!gui_cursor_mode) + { + ptr_input = hook_modifier_exec (NULL, + "input_text_display", + str_buffer, + (window->buffer->input_buffer) ? + window->buffer->input_buffer : ""); + } if (!ptr_input) { ptr_input = (window->buffer->input_buffer) ? @@ -791,13 +762,16 @@ gui_bar_item_default_input_text (void *data, struct t_gui_bar_item *item, } /* execute modifier with cursor in string */ - ptr_input2 = hook_modifier_exec (NULL, - "input_text_display_with_cursor", - str_buffer, - (ptr_input) ? ptr_input : ""); - if (ptr_input) - free (ptr_input); - ptr_input = ptr_input2; + if (!gui_cursor_mode) + { + ptr_input2 = hook_modifier_exec (NULL, + "input_text_display_with_cursor", + str_buffer, + (ptr_input) ? ptr_input : ""); + if (ptr_input) + free (ptr_input); + ptr_input = ptr_input2; + } /* insert "start input" at beginning of string */ if (ptr_input) @@ -1448,6 +1422,74 @@ gui_bar_item_default_buffer_nicklist (void *data, struct t_gui_bar_item *item, } /* + * gui_bar_item_focus_buffer_nicklist: focus on nicklist + */ + +struct t_hashtable * +gui_bar_item_focus_buffer_nicklist (void *data, + struct t_hashtable *info) +{ + struct t_gui_nick_group *ptr_group; + struct t_gui_nick *ptr_nick; + int i, rc, item_line; + unsigned long int value; + const char *str_window; + struct t_gui_window *window; + char *error; + + /* make C compiler happy */ + (void) data; + + str_window = hashtable_get (info, "_window"); + rc = sscanf (str_window, "%lx", &value); + if ((rc == EOF) || (rc == 0)) + return NULL; + + window = (struct t_gui_window *)value; + if (!window) + window = gui_current_window; + + error = NULL; + item_line = (int) strtol (hashtable_get (info, "_item_line"), &error, 10); + if (!error || error[0]) + return NULL; + + i = 0; + ptr_group = NULL; + ptr_nick = NULL; + gui_nicklist_get_next_item (window->buffer, &ptr_group, &ptr_nick); + while (ptr_group || ptr_nick) + { + if ((ptr_nick && ptr_nick->visible) + || (ptr_group && !ptr_nick + && window->buffer->nicklist_display_groups + && ptr_group->visible)) + { + if (i == item_line) + break; + i++; + } + gui_nicklist_get_next_item (window->buffer, &ptr_group, &ptr_nick); + } + + if (i != item_line) + return NULL; + + if (ptr_nick) + { + hashtable_set (info, "nick", ptr_nick->name); + hashtable_set (info, "prefix", ptr_nick->prefix); + } + else + { + hashtable_set (info, + "group", + gui_nicklist_get_group_start (ptr_group->name)); + } + return info; +} + +/* * gui_bar_item_timer_cb: timer callback */ @@ -1673,6 +1715,8 @@ gui_bar_item_init () gui_bar_item_names[GUI_BAR_ITEM_BUFFER_NICKLIST]); gui_bar_item_hook_signal ("buffer_switch", gui_bar_item_names[GUI_BAR_ITEM_BUFFER_NICKLIST]); + hook_focus (NULL, gui_bar_item_names[GUI_BAR_ITEM_BUFFER_NICKLIST], + &gui_bar_item_focus_buffer_nicklist, NULL); } /* diff --git a/src/gui/gui-bar-item.h b/src/gui/gui-bar-item.h index a6d8bdb06..bcc7b134b 100644 --- a/src/gui/gui-bar-item.h +++ b/src/gui/gui-bar-item.h @@ -74,13 +74,15 @@ extern char *gui_bar_items_default_for_bars[][2]; extern int gui_bar_item_valid (struct t_gui_bar_item *bar_item); extern struct t_gui_bar_item *gui_bar_item_search (const char *name); -extern int gui_bar_item_string_is_item (const char *string, - const char *item_name); extern int gui_bar_item_used_in_a_bar (const char *item_name, int partial_name); -extern char *gui_bar_item_get_value (const char *name, - struct t_gui_bar *bar, - struct t_gui_window *window); +extern void gui_bar_item_set_prefix_name_suffix (const char *item_name, + char **prefix, char **name, + char **suffix); +extern char *gui_bar_item_get_value (struct t_gui_bar *bar, + struct t_gui_window *window, + int item, int subitem); +extern int gui_bar_item_count_lines (char *string); extern struct t_gui_bar_item *gui_bar_item_new (struct t_weechat_plugin *plugin, const char *name, char *(*build_callback)(void *data, diff --git a/src/gui/gui-bar-window.c b/src/gui/gui-bar-window.c index 58cca2112..65069f187 100644 --- a/src/gui/gui-bar-window.c +++ b/src/gui/gui-bar-window.c @@ -26,14 +26,17 @@ #endif #include <stdlib.h> +#include <stddef.h> #include <limits.h> #include <string.h> #include "../core/weechat.h" #include "../core/wee-config.h" +#include "../core/wee-hdata.h" #include "../core/wee-infolist.h" #include "../core/wee-log.h" #include "../core/wee-string.h" +#include "../plugins/plugin.h" #include "gui-bar-window.h" #include "gui-bar.h" #include "gui-bar-item.h" @@ -102,6 +105,149 @@ gui_bar_window_search_bar (struct t_gui_window *window, struct t_gui_bar *bar) } /* + * gui_bar_window_search_by_xy: get bar_window pointer displayed at (x,y) + * if window is not NULL, search is done in + * bar windows of window + * if window is NULL, search is done in root + * bar windows + */ + +void +gui_bar_window_search_by_xy (struct t_gui_window *window, int x, int y, + struct t_gui_bar_window **bar_window, + char **bar_item, int *item_line, int *item_col) +{ + struct t_gui_bar *ptr_bar; + struct t_gui_bar_window *ptr_bar_window; + int filling, num_cols, column, lines, lines_old, i, j, coord_x, coord_y; + int item, subitem; + + *bar_window = NULL; + *bar_item = NULL; + *item_line = -1; + *item_col = -1; + + if (window) + { + for (ptr_bar_window = window->bar_windows; ptr_bar_window; + ptr_bar_window = ptr_bar_window->next_bar_window) + { + if ((x >= ptr_bar_window->x) && (y >= ptr_bar_window->y) + && (x <= ptr_bar_window->x + ptr_bar_window->width - 1) + && (y <= ptr_bar_window->y + ptr_bar_window->height - 1)) + { + *bar_window = ptr_bar_window; + break; + } + } + } + else + { + for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) + { + if (ptr_bar->bar_window + && (x >= ptr_bar->bar_window->x) + && (y >= ptr_bar->bar_window->y) + && (x <= ptr_bar->bar_window->x + ptr_bar->bar_window->width - 1) + && (y <= ptr_bar->bar_window->y + ptr_bar->bar_window->height - 1)) + { + *bar_window = ptr_bar->bar_window; + break; + } + } + } + + if (*bar_window) + { + filling = gui_bar_get_filling ((*bar_window)->bar); + + *item_line = y - (*bar_window)->y + (*bar_window)->scroll_y; + *item_col = x - (*bar_window)->x + (*bar_window)->scroll_x; + + if ((filling == GUI_BAR_FILLING_COLUMNS_HORIZONTAL) + && ((*bar_window)->screen_col_size > 0)) + { + num_cols = (*bar_window)->width / (*bar_window)->screen_col_size; + column = *item_col / (*bar_window)->screen_col_size; + *item_line = (*item_line * num_cols) + column; + *item_col = *item_col - (column * ((*bar_window)->screen_col_size)); + } + + if ((filling == GUI_BAR_FILLING_COLUMNS_VERTICAL) + && ((*bar_window)->screen_col_size > 0)) + { + column = *item_col / (*bar_window)->screen_col_size; + *item_line = (column * ((*bar_window)->height)) + *item_line; + *item_col = *item_col % ((*bar_window)->screen_col_size); + } + + if (filling == GUI_BAR_FILLING_HORIZONTAL) + { + i = 0; + while (i < (*bar_window)->coords_count) + { + coord_x = (*bar_window)->coords[i]->x; + coord_y = (*bar_window)->coords[i]->y; + while ((i < (*bar_window)->coords_count - 1) + && (coord_x == (*bar_window)->coords[i + 1]->x) + && (coord_y == (*bar_window)->coords[i + 1]->y)) + { + i++; + } + if (i == (*bar_window)->coords_count - 1) + { + item = (*bar_window)->coords[i]->item; + subitem = (*bar_window)->coords[i]->subitem; + if ((item >= 0) && (subitem >= 0)) + { + *bar_item = (*bar_window)->bar->items_name[item][subitem]; + *item_line = (*bar_window)->coords[i]->line; + *item_col = x - (*bar_window)->coords[i]->x; + } + break; + } + coord_x = (*bar_window)->coords[i + 1]->x; + coord_y = (*bar_window)->coords[i + 1]->y; + if ((y < coord_y) || ((y == coord_y) && (x < coord_x))) + { + item = (*bar_window)->coords[i]->item; + subitem = (*bar_window)->coords[i]->subitem; + *bar_item = (*bar_window)->bar->items_name[item][subitem]; + *item_line = (*bar_window)->coords[i]->line; + *item_col = x - (*bar_window)->coords[i]->x; + break; + } + i++; + } + } + else + { + i = 0; + j = 0; + lines = 0; + lines_old = 0; + while (i < (*bar_window)->items_count) + { + lines_old = lines; + lines += (*bar_window)->items_num_lines[i][j]; + if (*item_line < lines) + { + *bar_item = (*bar_window)->bar->items_name[i][j]; + break; + } + j++; + if (j >= (*bar_window)->items_subcount[i]) + { + j = 0; + i++; + } + } + *item_line -= lines_old; + } + } +} + +/* * gui_bar_window_get_size: get total bar size (window bars) for a position * bar is optional, if not NULL, size is computed * from bar 1 to bar # - 1 @@ -159,6 +305,9 @@ gui_bar_window_calculate_pos_size (struct t_gui_bar_window *bar_window, int x1, y1, x2, y2; int add_bottom, add_top, add_left, add_right; + if (CONFIG_BOOLEAN(bar_window->bar->options[GUI_BAR_OPTION_HIDDEN])) + return; + if (window) { x1 = window->win_x; @@ -247,7 +396,9 @@ gui_bar_window_content_alloc (struct t_gui_bar_window *bar_window) bar_window->items_count = bar_window->bar->items_count; bar_window->items_subcount = NULL; bar_window->items_content = NULL; + bar_window->items_num_lines = NULL; bar_window->items_refresh_needed = NULL; + bar_window->screen_col_size = 0; bar_window->items_subcount = malloc (bar_window->items_count * sizeof (*bar_window->items_subcount)); if (!bar_window->items_subcount) @@ -256,6 +407,10 @@ gui_bar_window_content_alloc (struct t_gui_bar_window *bar_window) sizeof (*bar_window->items_content)); if (!bar_window->items_content) goto error; + bar_window->items_num_lines = malloc ((bar_window->items_count) * + sizeof (*bar_window->items_num_lines)); + if (!bar_window->items_num_lines) + goto error; bar_window->items_refresh_needed = malloc (bar_window->items_count * sizeof (*bar_window->items_refresh_needed)); if (!bar_window->items_refresh_needed) @@ -264,6 +419,7 @@ gui_bar_window_content_alloc (struct t_gui_bar_window *bar_window) for (i = 0; i < bar_window->items_count; i++) { bar_window->items_content[i] = NULL; + bar_window->items_num_lines[i] = NULL; bar_window->items_refresh_needed[i] = NULL; } @@ -274,6 +430,10 @@ gui_bar_window_content_alloc (struct t_gui_bar_window *bar_window) sizeof (**bar_window->items_content)); if (!bar_window->items_content[i]) goto error; + bar_window->items_num_lines[i] = malloc (bar_window->items_subcount[i] * + sizeof (**bar_window->items_num_lines)); + if (!bar_window->items_num_lines[i]) + goto error; bar_window->items_refresh_needed[i] = malloc (bar_window->items_subcount[i] * sizeof (**bar_window->items_refresh_needed)); if (!bar_window->items_refresh_needed[i]) @@ -282,6 +442,8 @@ gui_bar_window_content_alloc (struct t_gui_bar_window *bar_window) { if (bar_window->items_content[i]) bar_window->items_content[i][j] = NULL; + if (bar_window->items_num_lines[i]) + bar_window->items_num_lines[i][j] = 0; if (bar_window->items_refresh_needed[i]) bar_window->items_refresh_needed[i][j] = 1; } @@ -304,6 +466,16 @@ error: free (bar_window->items_content); bar_window->items_content = NULL; } + if (bar_window->items_num_lines) + { + for (i = 0; i < bar_window->items_count; i++) + { + if (bar_window->items_num_lines[i]) + free (bar_window->items_num_lines[i]); + } + free (bar_window->items_num_lines); + bar_window->items_num_lines = NULL; + } if (bar_window->items_refresh_needed) { for (i = 0; i < bar_window->items_count; i++) @@ -338,12 +510,15 @@ gui_bar_window_content_free (struct t_gui_bar_window *bar_window) } } free (bar_window->items_content[i]); + free (bar_window->items_num_lines[i]); free (bar_window->items_refresh_needed[i]); } free (bar_window->items_subcount); bar_window->items_subcount = NULL; free (bar_window->items_content); bar_window->items_content = NULL; + free (bar_window->items_num_lines); + bar_window->items_num_lines = NULL; free (bar_window->items_refresh_needed); bar_window->items_refresh_needed = NULL; } @@ -368,14 +543,17 @@ gui_bar_window_content_build_item (struct t_gui_bar_window *bar_window, free (bar_window->items_content[index_item][index_subitem]); bar_window->items_content[index_item][index_subitem] = NULL; } + bar_window->items_num_lines[index_item][index_subitem] = 0; /* build item, but only if there's a buffer in window */ if ((window && window->buffer) || (gui_current_window && gui_current_window->buffer)) { bar_window->items_content[index_item][index_subitem] = - gui_bar_item_get_value (bar_window->bar->items_array[index_item][index_subitem], - bar_window->bar, window); + gui_bar_item_get_value (bar_window->bar, window, + index_item, index_subitem); + bar_window->items_num_lines[index_item][index_subitem] = + gui_bar_item_count_lines (bar_window->items_content[index_item][index_subitem]); bar_window->items_refresh_needed[index_item][index_subitem] = 0; } } @@ -437,28 +615,50 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, struct t_gui_window *window) { enum t_gui_bar_filling filling; - char *ptr_content, *content, reinit_color[32], reinit_color_space[32]; + char *ptr_content, *content, str_reinit_color[32]; + char str_reinit_color_space[32], str_reinit_color_space_start_line[32]; + char str_start_item[32]; char *item_value, *item_value2, ****split_items, **linear_items; - int index_content, content_length, i, first_sub_item, sub, j, k, index; - int length_reinit_color_space, length, max_length, max_length_screen; + int index_content, content_length, i, j, k, sub, index; + int at_least_one_item, first_sub_item; + int length_reinit_color_space, length_start_item, length; + int max_length, max_length_screen; int total_items, columns, lines; if (!bar_window->items_subcount || !bar_window->items_content - || !bar_window->items_refresh_needed) + || !bar_window->items_num_lines || !bar_window->items_refresh_needed) return NULL; - snprintf (reinit_color, sizeof (reinit_color), + snprintf (str_reinit_color, sizeof (str_reinit_color), "%c", GUI_COLOR_RESET_CHAR); - snprintf (reinit_color_space, sizeof (reinit_color_space), + snprintf (str_reinit_color_space, sizeof (str_reinit_color_space), "%c ", GUI_COLOR_RESET_CHAR); - length_reinit_color_space = strlen (reinit_color_space); + length_reinit_color_space = strlen (str_reinit_color_space); + + snprintf (str_reinit_color_space_start_line, + sizeof (str_reinit_color_space_start_line), + "%c %c%c%c", + GUI_COLOR_RESET_CHAR, + GUI_COLOR_COLOR_CHAR, + GUI_COLOR_BAR_CHAR, + GUI_COLOR_BAR_START_LINE_ITEM); + + snprintf (str_start_item, sizeof (str_start_item), + "%c%c%c", + GUI_COLOR_COLOR_CHAR, + GUI_COLOR_BAR_CHAR, + GUI_COLOR_BAR_START_ITEM); + length_start_item = strlen (str_start_item); - content = NULL; content_length = 1; + content = malloc (content_length); + if (content) + content[0] = '\0'; filling = gui_bar_get_filling (bar_window->bar); + at_least_one_item = 0; switch (filling) { case GUI_BAR_FILLING_HORIZONTAL: /* items separated by space */ @@ -472,10 +672,10 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, i, sub); if (ptr_content && ptr_content[0]) { - if (gui_bar_get_filling (bar_window->bar) == GUI_BAR_FILLING_HORIZONTAL) + if (filling == GUI_BAR_FILLING_HORIZONTAL) { item_value = string_replace (ptr_content, "\n", - reinit_color_space); + str_reinit_color_space_start_line); if (item_value) { item_value2 = string_replace (item_value, @@ -489,43 +689,55 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, } else item_value = NULL; - if (!content) + + content_length += ((filling == GUI_BAR_FILLING_HORIZONTAL) ? length_start_item : 0) + + length_reinit_color_space + + strlen ((item_value) ? item_value : ptr_content); + content = realloc (content, content_length); + if (at_least_one_item && first_sub_item) { - content_length += strlen ((item_value) ? - item_value : ptr_content); - content = strdup ((item_value) ? item_value : ptr_content); - first_sub_item = 0; + /* first sub item: insert space after last item */ + if (filling == GUI_BAR_FILLING_HORIZONTAL) + strcat (content, str_reinit_color_space); + else + strcat (content, "\n"); } else { - content_length += length_reinit_color_space + - strlen ((item_value) ? item_value : ptr_content); - content = realloc (content, content_length); - if (first_sub_item) - { - /* first sub item: insert space after last item */ - if (gui_bar_get_filling (bar_window->bar) == GUI_BAR_FILLING_HORIZONTAL) - strcat (content, reinit_color_space); - else - strcat (content, "\n"); - } - else - { - strcat (content, reinit_color); - } - strcat (content, - (item_value) ? item_value : ptr_content); - first_sub_item = 0; + strcat (content, str_reinit_color); } + if (filling == GUI_BAR_FILLING_HORIZONTAL) + strcat (content, str_start_item); + strcat (content, + (item_value) ? item_value : ptr_content); + first_sub_item = 0; + if (item_value) free (item_value); + at_least_one_item = 1; + } + else + { + if (filling == GUI_BAR_FILLING_HORIZONTAL) + { + content_length += length_start_item; + content = realloc (content, content_length); + if (content) + strcat (content, str_start_item); + } } } } + if (filling == GUI_BAR_FILLING_HORIZONTAL) + { + content_length += length_start_item; + content = realloc (content, content_length); + if (content) + strcat (content, str_start_item); + } break; case GUI_BAR_FILLING_COLUMNS_HORIZONTAL: /* items in columns, with horizontal filling */ case GUI_BAR_FILLING_COLUMNS_VERTICAL: /* items in columns, with vertical filling */ - content = NULL; total_items = 0; max_length = 1; max_length_screen = 1; @@ -580,6 +792,7 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, columns++; lines = bar_window->height; } + bar_window->screen_col_size = max_length_screen + 1; /* build array with pointers to split items */ @@ -605,9 +818,10 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, } /* build content with lines and columns */ - content = malloc (1 + (lines * - ((columns * - (max_length + max_length_screen + length_reinit_color_space)) + 1))); + content_length = 1 + (lines * + ((columns * + (max_length + max_length_screen + length_reinit_color_space)) + 1)); + content = realloc (content, content_length); if (content) { content[0] = '\0'; @@ -641,7 +855,8 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, } if (j < columns - 1) { - strcpy (content + index_content, reinit_color_space); + strcpy (content + index_content, + str_reinit_color_space); index_content += length_reinit_color_space; } } @@ -671,25 +886,126 @@ gui_bar_window_content_get_with_filling (struct t_gui_bar_window *bar_window, break; } + if (content_length == 1) + { + free (content); + content = NULL; + } + return content; } /* + * gui_bar_window_coords_add: add coordinates (item index/subindex and x,y) + */ + +void +gui_bar_window_coords_add (struct t_gui_bar_window *bar_window, + int index_item, int index_subitem, int index_line, + int x, int y) +{ + if (!bar_window->coords) + { + bar_window->coords_count = 1; + bar_window->coords = malloc (sizeof (*(bar_window->coords))); + } + else + { + bar_window->coords_count++; + bar_window->coords = realloc (bar_window->coords, + bar_window->coords_count * sizeof (*(bar_window->coords))); + } + bar_window->coords[bar_window->coords_count - 1] = malloc (sizeof (*(bar_window->coords[bar_window->coords_count - 1]))); + bar_window->coords[bar_window->coords_count - 1]->item = index_item; + bar_window->coords[bar_window->coords_count - 1]->subitem = index_subitem; + bar_window->coords[bar_window->coords_count - 1]->line = index_line; + bar_window->coords[bar_window->coords_count - 1]->x = x; + bar_window->coords[bar_window->coords_count - 1]->y = y; +} + +/* + * gui_bar_window_coords_free: free coords of a bar window + */ + +void +gui_bar_window_coords_free (struct t_gui_bar_window *bar_window) +{ + int i; + + if (bar_window->coords) + { + for (i = 0; i < bar_window->coords_count; i++) + { + free (bar_window->coords[i]); + } + free (bar_window->coords); + bar_window->coords = NULL; + } + bar_window->coords_count = 0; +} + +/* + * gui_bar_window_insert: insert bar window in list of bar windows (at good + * position, according to priority) + */ + +void +gui_bar_window_insert (struct t_gui_bar_window *bar_window, + struct t_gui_window *window) +{ + struct t_gui_bar_window *pos_bar_window; + + if (window->bar_windows) + { + pos_bar_window = gui_bar_window_find_pos (bar_window->bar, window); + if (pos_bar_window) + { + /* insert before bar window found */ + bar_window->prev_bar_window = pos_bar_window->prev_bar_window; + bar_window->next_bar_window = pos_bar_window; + if (pos_bar_window->prev_bar_window) + (pos_bar_window->prev_bar_window)->next_bar_window = bar_window; + else + window->bar_windows = bar_window; + pos_bar_window->prev_bar_window = bar_window; + } + else + { + /* add to end of list for window */ + bar_window->prev_bar_window = window->last_bar_window; + bar_window->next_bar_window = NULL; + (window->last_bar_window)->next_bar_window = bar_window; + window->last_bar_window = bar_window; + } + } + else + { + bar_window->prev_bar_window = NULL; + bar_window->next_bar_window = NULL; + window->bar_windows = bar_window; + window->last_bar_window = bar_window; + } +} + +/* * gui_bar_window_new: create a new "window bar" for a bar, in screen or a window * if window is not NULL, bar window will be in this window * return 1 if ok, 0 if error */ -int +void gui_bar_window_new (struct t_gui_bar *bar, struct t_gui_window *window) { - struct t_gui_bar_window *new_bar_window, *pos_bar_window; + struct t_gui_bar_window *new_bar_window; + + if (CONFIG_BOOLEAN(bar->options[GUI_BAR_OPTION_HIDDEN])) + return; if (window) { if ((CONFIG_INTEGER(bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_WINDOW) && (!gui_bar_check_conditions_for_window (bar, window))) - return 1; + return; } new_bar_window = malloc (sizeof (*new_bar_window)); @@ -699,36 +1015,7 @@ gui_bar_window_new (struct t_gui_bar *bar, struct t_gui_window *window) if (window) { bar->bar_window = NULL; - if (window->bar_windows) - { - pos_bar_window = gui_bar_window_find_pos (bar, window); - if (pos_bar_window) - { - /* insert before bar window found */ - new_bar_window->prev_bar_window = pos_bar_window->prev_bar_window; - new_bar_window->next_bar_window = pos_bar_window; - if (pos_bar_window->prev_bar_window) - (pos_bar_window->prev_bar_window)->next_bar_window = new_bar_window; - else - window->bar_windows = new_bar_window; - pos_bar_window->prev_bar_window = new_bar_window; - } - else - { - /* add to end of list for window */ - new_bar_window->prev_bar_window = window->last_bar_window; - new_bar_window->next_bar_window = NULL; - (window->last_bar_window)->next_bar_window = new_bar_window; - window->last_bar_window = new_bar_window; - } - } - else - { - new_bar_window->prev_bar_window = NULL; - new_bar_window->next_bar_window = NULL; - window->bar_windows = new_bar_window; - window->last_bar_window = new_bar_window; - } + gui_bar_window_insert (new_bar_window, window); } else { @@ -750,7 +1037,11 @@ gui_bar_window_new (struct t_gui_bar *bar, struct t_gui_window *window) new_bar_window->items_count = 0; new_bar_window->items_subcount = NULL; new_bar_window->items_content = NULL; + new_bar_window->items_num_lines = NULL; new_bar_window->items_refresh_needed = NULL; + new_bar_window->screen_col_size = 0; + new_bar_window->coords_count = 0; + new_bar_window->coords = NULL; gui_bar_window_objects_init (new_bar_window); gui_bar_window_content_alloc (new_bar_window); @@ -760,12 +1051,7 @@ gui_bar_window_new (struct t_gui_bar *bar, struct t_gui_window *window) gui_bar_window_create_win (new_bar_window); gui_window_ask_refresh (1); } - - return 1; } - - /* failed to create bar window */ - return 0; } /* @@ -916,6 +1202,7 @@ gui_bar_window_free (struct t_gui_bar_window *bar_window, /* free data */ gui_bar_window_content_free (bar_window); + gui_bar_window_coords_free (bar_window); gui_bar_window_objects_free (bar_window); free (bar_window->gui_objects); @@ -1060,6 +1347,46 @@ gui_bar_window_scroll (struct t_gui_bar_window *bar_window, } /* + * gui_bar_window_hdata_bar_window_cb: return hdata for bar window + */ + +struct t_hdata * +gui_bar_window_hdata_bar_window_cb (void *data, const char *hdata_name) +{ + struct t_hdata *hdata; + + /* make C compiler happy */ + (void) data; + + hdata = hdata_new (NULL, hdata_name, "prev_bar_window", "next_bar_window"); + if (hdata) + { + HDATA_VAR(struct t_gui_bar_window, bar, POINTER, "bar"); + HDATA_VAR(struct t_gui_bar_window, x, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, y, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, width, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, height, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, scroll_x, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, scroll_y, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, cursor_x, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, cursor_y, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, current_size, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, items_count, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, items_subcount, POINTER, NULL); + HDATA_VAR(struct t_gui_bar_window, items_content, POINTER, NULL); + HDATA_VAR(struct t_gui_bar_window, items_num_lines, POINTER, NULL); + HDATA_VAR(struct t_gui_bar_window, items_refresh_needed, POINTER, NULL); + HDATA_VAR(struct t_gui_bar_window, screen_col_size, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, coords_count, INTEGER, NULL); + HDATA_VAR(struct t_gui_bar_window, coords, POINTER, NULL); + HDATA_VAR(struct t_gui_bar_window, gui_objects, POINTER, NULL); + HDATA_VAR(struct t_gui_bar_window, prev_bar_window, POINTER, hdata_name); + HDATA_VAR(struct t_gui_bar_window, next_bar_window, POINTER, hdata_name); + } + return hdata; +} + +/* * gui_bar_window_add_to_infolist: add a bar window in an infolist * return 1 if ok, 0 if error */ @@ -1110,8 +1437,15 @@ gui_bar_window_add_to_infolist (struct t_infolist *infolist, if (!infolist_new_var_string (ptr_item, option_name, bar_window->items_content[i][j])) return 0; + snprintf (option_name, sizeof (option_name), + "items_num_lines_%05d_%05d", i + 1, j + 1); + if (!infolist_new_var_integer (ptr_item, option_name, + bar_window->items_num_lines[i][j])) + return 0; } } + if (!infolist_new_var_integer (ptr_item, "screen_col_size", bar_window->screen_col_size)) + return 0; if (!infolist_new_var_pointer (ptr_item, "gui_objects", bar_window->gui_objects)) return 0; @@ -1151,11 +1485,13 @@ gui_bar_window_print_log (struct t_gui_bar_window *bar_window) { for (j = 0; j < bar_window->items_subcount[i]; j++) { - log_printf (" items_content[%03d][%03d]: '%s' (item: '%s')", + log_printf (" items_content[%03d][%03d]: '%s' " + "(item: '%s', num_lines: %d)", i, j, bar_window->items_content[i][j], (bar_window->items_count >= i + 1) ? - bar_window->bar->items_array[i][j] : "?"); + bar_window->bar->items_array[i][j] : "?", + bar_window->items_num_lines[i][j]); } } else @@ -1163,6 +1499,19 @@ gui_bar_window_print_log (struct t_gui_bar_window *bar_window) log_printf (" items_content. . . . . . : 0x%lx", bar_window->items_content); } } + log_printf (" screen_col_size. . . . : %d", bar_window->screen_col_size); + log_printf (" coords_count . . . . . : %d", bar_window->coords_count); + for (i = 0; i < bar_window->coords_count; i++) + { + log_printf (" coords[%03d]. . . . . . : item=%d, subitem=%d, " + "line=%d, x=%d, y=%d", + i, + bar_window->coords[i]->item, + bar_window->coords[i]->subitem, + bar_window->coords[i]->line, + bar_window->coords[i]->x, + bar_window->coords[i]->y); + } log_printf (" gui_objects. . . . . . : 0x%lx", bar_window->gui_objects); gui_bar_window_objects_print_log (bar_window); log_printf (" prev_bar_window. . . . : 0x%lx", bar_window->prev_bar_window); diff --git a/src/gui/gui-bar-window.h b/src/gui/gui-bar-window.h index ddaeebbe3..337e9254e 100644 --- a/src/gui/gui-bar-window.h +++ b/src/gui/gui-bar-window.h @@ -20,9 +20,19 @@ #ifndef __WEECHAT_GUI_BAR_WINDOW_H #define __WEECHAT_GUI_BAR_WINDOW_H 1 +struct t_infolist; struct t_gui_window; enum t_gui_bar_position; +struct t_gui_bar_window_coords +{ + int item; /* index of item */ + int subitem; /* index of sub item */ + int line; /* line */ + int x; /* X on screen */ + int y; /* Y on screen */ +}; + struct t_gui_bar_window { struct t_gui_bar *bar; /* pointer to bar */ @@ -34,8 +44,14 @@ struct t_gui_bar_window int current_size; /* current size (width or height) */ int items_count; /* number of bar items */ int *items_subcount; /* number of sub items */ - char ***items_content; /* content for each item/sub item of bar*/ + char ***items_content; /* content for each (sub)item of bar */ + int **items_num_lines; /* number of lines for each (sub)item */ int **items_refresh_needed; /* refresh needed for (sub)item? */ + int screen_col_size; /* size of columns on screen */ + /* (for filling with columns) */ + int coords_count; /* number of coords saved */ + struct t_gui_bar_window_coords **coords; /* coords for filling horiz. */ + /* (size is 5 * coords_count) */ void *gui_objects; /* pointer to a GUI specific struct */ struct t_gui_bar_window *prev_bar_window; /* link to previous bar win */ /* (only for non-root bars) */ @@ -46,6 +62,12 @@ struct t_gui_bar_window /* functions */ extern int gui_bar_window_valid (struct t_gui_bar_window *bar_window); +extern void gui_bar_window_search_by_xy (struct t_gui_window *window, + int x, int y, + struct t_gui_bar_window **bar_window, + char **bar_item, + int *item_line, + int *item_col); extern void gui_bar_window_calculate_pos_size (struct t_gui_bar_window *bar_window, struct t_gui_window *window); extern void gui_bar_window_content_build (struct t_gui_bar_window *bar_window, @@ -61,8 +83,15 @@ extern void gui_bar_window_set_current_size (struct t_gui_bar_window *bar_window extern int gui_bar_window_get_size (struct t_gui_bar *bar, struct t_gui_window *window, enum t_gui_bar_position position); -extern int gui_bar_window_new (struct t_gui_bar *bar, - struct t_gui_window *window); +extern void gui_bar_window_coords_add (struct t_gui_bar_window *bar_window, + int index_item, int index_subitem, + int index_line, + int x, int y); +extern void gui_bar_window_coords_free (struct t_gui_bar_window *bar_window); +extern void gui_bar_window_insert (struct t_gui_bar_window *bar_window, + struct t_gui_window *window); +extern void gui_bar_window_new (struct t_gui_bar *bar, + struct t_gui_window *window); extern void gui_bar_window_free (struct t_gui_bar_window *bar_window, struct t_gui_window *window); extern int gui_bar_window_remove_unused_bars (struct t_gui_window *window); @@ -72,6 +101,8 @@ extern void gui_bar_window_scroll (struct t_gui_bar_window *bar_window, int add_x, int scroll_beginning, int scroll_end, int add, int percent, int value); +extern struct t_hdata *gui_bar_window_hdata_bar_window_cb (void *data, + const char *hdata_name); extern int gui_bar_window_add_to_infolist (struct t_infolist *infolist, struct t_gui_bar_window *bar_window); extern void gui_bar_window_print_log (struct t_gui_bar_window *bar_window); diff --git a/src/gui/gui-bar.c b/src/gui/gui-bar.c index 381f4fdcb..d7ec19aee 100644 --- a/src/gui/gui-bar.c +++ b/src/gui/gui-bar.c @@ -637,24 +637,54 @@ gui_bar_apply_current_size (struct t_gui_bar *bar) } /* - * gui_bar_free_items_array: free array with items for a bar + * gui_bar_free_items_arrays: free arrays with items for a bar */ void -gui_bar_free_items_array (struct t_gui_bar *bar) +gui_bar_free_items_arrays (struct t_gui_bar *bar) { - int i; + int i, j; for (i = 0; i < bar->items_count; i++) { if (bar->items_array[i]) string_free_split (bar->items_array[i]); + for (j = 0; j < bar->items_subcount[i]; j++) + { + if (bar->items_prefix[i][j]) + free (bar->items_prefix[i][j]); + if (bar->items_name[i][j]) + free (bar->items_name[i][j]); + if (bar->items_suffix[i][j]) + free (bar->items_suffix[i][j]); + } + if (bar->items_prefix[i]) + free (bar->items_prefix[i]); + if (bar->items_name[i]) + free (bar->items_name[i]); + if (bar->items_suffix[i]) + free (bar->items_suffix[i]); } if (bar->items_array) { free (bar->items_array); bar->items_array = NULL; } + if (bar->items_prefix) + { + free (bar->items_prefix); + bar->items_prefix = NULL; + } + if (bar->items_name) + { + free (bar->items_name); + bar->items_name = NULL; + } + if (bar->items_suffix) + { + free (bar->items_suffix); + bar->items_suffix = NULL; + } if (bar->items_subcount) { free (bar->items_subcount); @@ -670,10 +700,10 @@ gui_bar_free_items_array (struct t_gui_bar *bar) void gui_bar_set_items_array (struct t_gui_bar *bar, const char *items) { - int i, count; + int i, j, count; char **tmp_array; - gui_bar_free_items_array (bar); + gui_bar_free_items_arrays (bar); if (items && items[0]) { @@ -683,10 +713,29 @@ gui_bar_set_items_array (struct t_gui_bar *bar, const char *items) bar->items_count = count; bar->items_subcount = malloc (count * sizeof (*bar->items_subcount)); bar->items_array = malloc (count * sizeof (*bar->items_array)); + bar->items_prefix = malloc (count * sizeof (*bar->items_prefix)); + bar->items_name = malloc (count * sizeof (*bar->items_name)); + bar->items_suffix = malloc (count * sizeof (*bar->items_suffix)); for (i = 0; i < count; i++) { bar->items_array[i] = string_split (tmp_array[i], "+", 0, 0, &(bar->items_subcount[i])); + if (bar->items_subcount[i] > 0) + { + bar->items_prefix[i] = malloc (bar->items_subcount[i] * + sizeof (*(bar->items_prefix[i]))); + bar->items_name[i] = malloc (bar->items_subcount[i] * + sizeof (*(bar->items_name[i]))); + bar->items_suffix[i] = malloc (bar->items_subcount[i] * + sizeof (*(bar->items_suffix[i]))); + for (j = 0; j < bar->items_subcount[i]; j++) + { + gui_bar_item_set_prefix_name_suffix (bar->items_array[i][j], + &bar->items_prefix[i][j], + &bar->items_name[i][j], + &bar->items_suffix[i][j]); + } + } } } string_free_split (tmp_array); @@ -722,6 +771,8 @@ gui_bar_config_change_hidden (void *data, struct t_config_option *option) { struct t_gui_bar *ptr_bar; struct t_gui_window *ptr_win; + struct t_gui_bar_window *ptr_bar_win; + int bar_window_exists; /* make C compiler happy */ (void) data; @@ -729,26 +780,43 @@ gui_bar_config_change_hidden (void *data, struct t_config_option *option) ptr_bar = gui_bar_search_with_option_name (option->name); if (ptr_bar) { - /* free bar windows */ - for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) + if (CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_ROOT) { - gui_bar_free_bar_windows (ptr_bar); + if (CONFIG_BOOLEAN(ptr_bar->options[GUI_BAR_OPTION_HIDDEN])) + { + gui_bar_window_free (ptr_bar->bar_window, NULL); + ptr_bar->bar_window = NULL; + } + else + { + gui_bar_window_new (ptr_bar, NULL); + } } - - for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + else { - for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) { - if (!CONFIG_BOOLEAN(ptr_bar->options[GUI_BAR_OPTION_HIDDEN]) - && (CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE]) != GUI_BAR_TYPE_ROOT)) + bar_window_exists = 0; + for (ptr_bar_win = ptr_win->bar_windows; ptr_bar_win; + ptr_bar_win = ptr_bar_win->next_bar_window) + { + if (ptr_bar_win->bar == ptr_bar) + { + if (CONFIG_BOOLEAN(ptr_bar->options[GUI_BAR_OPTION_HIDDEN])) + gui_bar_window_free (ptr_bar_win, ptr_win); + else + bar_window_exists = 1; + } + } + if (!bar_window_exists + && !CONFIG_BOOLEAN(ptr_bar->options[GUI_BAR_OPTION_HIDDEN])) { gui_bar_window_new (ptr_bar, ptr_win); } } } + gui_window_ask_refresh (1); } - - gui_window_ask_refresh (1); } /* @@ -760,6 +828,7 @@ gui_bar_config_change_priority (void *data, struct t_config_option *option) { struct t_gui_bar *ptr_bar; struct t_gui_window *ptr_win; + struct t_gui_bar_window *bar_windows, *ptr_bar_win, *next_bar_win; /* make C compiler happy */ (void) data; @@ -785,26 +854,24 @@ gui_bar_config_change_priority (void *data, struct t_config_option *option) gui_bar_insert (ptr_bar); - /* free bar windows */ - for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) - { - gui_bar_free_bar_windows (ptr_bar); - } - for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) { - for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) + bar_windows = ptr_win->bar_windows; + ptr_win->bar_windows = NULL; + ptr_win->last_bar_window = NULL; + ptr_bar_win = bar_windows; + while (ptr_bar_win) { - if (!CONFIG_BOOLEAN(ptr_bar->options[GUI_BAR_OPTION_HIDDEN]) - && (CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE]) != GUI_BAR_TYPE_ROOT)) - { - gui_bar_window_new (ptr_bar, ptr_win); - } + next_bar_win = ptr_bar_win->next_bar_window; + + gui_bar_window_insert (ptr_bar_win, ptr_win); + + ptr_bar_win = next_bar_win; } } + + gui_window_ask_refresh (1); } - - gui_window_ask_refresh (1); } /* @@ -1468,6 +1535,9 @@ gui_bar_alloc (const char *name) new_bar->conditions_array = NULL; new_bar->items_count = 0; new_bar->items_array = NULL; + new_bar->items_prefix = NULL; + new_bar->items_name = NULL; + new_bar->items_suffix = NULL; new_bar->bar_window = NULL; new_bar->bar_refresh_needed = 0; new_bar->prev_bar = NULL; @@ -1533,6 +1603,9 @@ gui_bar_new_with_options (const char *name, new_bar->items_count = 0; new_bar->items_subcount = NULL; new_bar->items_array = NULL; + new_bar->items_prefix = NULL; + new_bar->items_name = NULL; + new_bar->items_suffix = NULL; gui_bar_set_items_array (new_bar, CONFIG_STRING(items)); new_bar->bar_window = NULL; new_bar->bar_refresh_needed = 1; @@ -1983,7 +2056,11 @@ gui_bar_scroll (struct t_gui_bar *bar, struct t_gui_buffer *buffer, scroll++; } else - return 0; + { + /* auto-detect if we scroll X/Y, according to filling */ + if (gui_bar_get_filling (bar) == GUI_BAR_FILLING_HORIZONTAL) + add_x = 1; + } if ((scroll[0] == 'b') || (scroll[0] == 'B')) { @@ -2032,9 +2109,11 @@ gui_bar_scroll (struct t_gui_bar *bar, struct t_gui_buffer *buffer, } if (CONFIG_INTEGER(bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_ROOT) + { gui_bar_window_scroll (bar->bar_window, NULL, add_x, scroll_beginning, scroll_end, add, percent, number); + } else { for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) @@ -2055,7 +2134,8 @@ gui_bar_scroll (struct t_gui_bar *bar, struct t_gui_buffer *buffer, } } - free (str); + if (str) + free (str); return 1; } @@ -2101,7 +2181,7 @@ gui_bar_free (struct t_gui_bar *bar) } if (bar->conditions_array) string_free_split (bar->conditions_array); - gui_bar_free_items_array (bar); + gui_bar_free_items_arrays (bar); free (bar); } @@ -2129,17 +2209,25 @@ gui_bar_free_bar_windows (struct t_gui_bar *bar) struct t_gui_window *ptr_win; struct t_gui_bar_window *ptr_bar_win, *next_bar_win; - for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + if (bar->bar_window) { - ptr_bar_win = ptr_win->bar_windows; - while (ptr_bar_win) + gui_bar_window_free (bar->bar_window, NULL); + bar->bar_window = NULL; + } + else + { + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) { - next_bar_win = ptr_bar_win->next_bar_window; - - if (ptr_bar_win->bar == bar) - gui_bar_window_free (ptr_bar_win, ptr_win); - - ptr_bar_win = next_bar_win; + ptr_bar_win = ptr_win->bar_windows; + while (ptr_bar_win) + { + next_bar_win = ptr_bar_win->next_bar_window; + + if (ptr_bar_win->bar == bar) + gui_bar_window_free (ptr_bar_win, ptr_win); + + ptr_bar_win = next_bar_win; + } } } } @@ -2166,7 +2254,10 @@ gui_bar_hdata_bar_cb (void *data, const char *hdata_name) HDATA_VAR(struct t_gui_bar, items_count, INTEGER, NULL); HDATA_VAR(struct t_gui_bar, items_subcount, POINTER, NULL); HDATA_VAR(struct t_gui_bar, items_array, POINTER, NULL); - HDATA_VAR(struct t_gui_bar, bar_window, POINTER, NULL); + HDATA_VAR(struct t_gui_bar, items_prefix, POINTER, NULL); + HDATA_VAR(struct t_gui_bar, items_name, POINTER, NULL); + HDATA_VAR(struct t_gui_bar, items_suffix, POINTER, NULL); + HDATA_VAR(struct t_gui_bar, bar_window, POINTER, "bar_window"); HDATA_VAR(struct t_gui_bar, bar_refresh_needed, INTEGER, NULL); HDATA_VAR(struct t_gui_bar, prev_bar, POINTER, hdata_name); HDATA_VAR(struct t_gui_bar, next_bar, POINTER, hdata_name); @@ -2247,6 +2338,16 @@ gui_bar_add_to_infolist (struct t_infolist *infolist, if (!infolist_new_var_string (ptr_item, option_name, bar->items_array[i][j])) return 0; + snprintf (option_name, sizeof (option_name), + "items_prefix_%05d_%05d", i + 1, j + 1); + if (!infolist_new_var_string (ptr_item, option_name, + bar->items_prefix[i][j])) + return 0; + snprintf (option_name, sizeof (option_name), + "items_suffix_%05d_%05d", i + 1, j + 1); + if (!infolist_new_var_string (ptr_item, option_name, + bar->items_suffix[i][j])) + return 0; } } if (!infolist_new_var_pointer (ptr_item, "bar_window", bar->bar_window)) @@ -2307,8 +2408,13 @@ gui_bar_print_log () i, ptr_bar->items_subcount[i]); for (j = 0; j < ptr_bar->items_subcount[i]; j++) { - log_printf (" items_array[%03d][%03d]: '%s'", - i, j, ptr_bar->items_array[i][j]); + log_printf (" items_array[%03d][%03d]: '%s' " + "(prefix: '%s', name: '%s', suffix: '%s')", + i, j, + ptr_bar->items_array[i][j], + ptr_bar->items_prefix[i][j], + ptr_bar->items_name[i][j], + ptr_bar->items_suffix[i][j]); } } log_printf (" bar_window . . . . . . : 0x%lx", ptr_bar->bar_window); diff --git a/src/gui/gui-bar.h b/src/gui/gui-bar.h index e53626fa5..cb5e8b8d8 100644 --- a/src/gui/gui-bar.h +++ b/src/gui/gui-bar.h @@ -20,6 +20,7 @@ #ifndef __WEECHAT_GUI_BAR_H #define __WEECHAT_GUI_BAR_H 1 +struct t_infolist; struct t_weechat_plugin; struct t_gui_window; struct t_gui_buffer; @@ -89,6 +90,9 @@ struct t_gui_bar int items_count; /* number of bar items */ int *items_subcount; /* number of sub items */ char ***items_array; /* bar items (after split) */ + char ***items_prefix; /* prefix for each (sub)item */ + char ***items_name; /* name for each (sub)item */ + char ***items_suffix; /* suffix for each (sub)item */ struct t_gui_bar_window *bar_window; /* pointer to bar window */ /* (for type root only) */ int bar_refresh_needed; /* refresh for bar is needed? */ diff --git a/src/gui/gui-color.c b/src/gui/gui-color.c index 66d3b4f33..1dc72ec0f 100644 --- a/src/gui/gui-color.c +++ b/src/gui/gui-color.c @@ -515,6 +515,8 @@ gui_color_decode (const char *string, const char *replacement) case GUI_COLOR_BAR_START_INPUT_CHAR: case GUI_COLOR_BAR_START_INPUT_HIDDEN_CHAR: case GUI_COLOR_BAR_MOVE_CURSOR_CHAR: + case GUI_COLOR_BAR_START_ITEM: + case GUI_COLOR_BAR_START_LINE_ITEM: ptr_string++; break; } diff --git a/src/gui/gui-color.h b/src/gui/gui-color.h index d4c6fb633..b0f114cfe 100644 --- a/src/gui/gui-color.h +++ b/src/gui/gui-color.h @@ -104,6 +104,8 @@ enum t_gui_color_enum #define GUI_COLOR_BAR_START_INPUT_CHAR '_' #define GUI_COLOR_BAR_START_INPUT_HIDDEN_CHAR '-' #define GUI_COLOR_BAR_MOVE_CURSOR_CHAR '#' +#define GUI_COLOR_BAR_START_ITEM 'i' +#define GUI_COLOR_BAR_START_LINE_ITEM 'l' #define GUI_COLOR_EXTENDED_FLAG 0x0100000 #define GUI_COLOR_EXTENDED_BOLD_FLAG 0x0200000 diff --git a/src/gui/gui-completion.c b/src/gui/gui-completion.c index 4bdcc9c98..6f6118b62 100644 --- a/src/gui/gui-completion.c +++ b/src/gui/gui-completion.c @@ -1027,7 +1027,7 @@ gui_completion_complete (struct t_gui_completion *completion) other_completion++; } if (completion->word_found && - (string_strcasecmp (ptr_item->data, completion->word_found) == 0)) + (strcmp (ptr_item->data, completion->word_found) == 0)) word_found_seen = 1; if (completion->direction < 0) diff --git a/src/gui/gui-cursor.c b/src/gui/gui-cursor.c new file mode 100644 index 000000000..f210826cf --- /dev/null +++ b/src/gui/gui-cursor.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2011 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * gui-cursor.c: functions for free movement of cursor (used by all GUI) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "../core/weechat.h" +#include "gui-cursor.h" +#include "gui-bar.h" +#include "gui-bar-window.h" +#include "gui-buffer.h" +#include "gui-chat.h" +#include "gui-color.h" +#include "gui-input.h" +#include "gui-window.h" + + +int gui_cursor_mode = 0; /* cursor mode? (free movement) */ +int gui_cursor_debug = 0; /* debug mode (show info in input) */ +int gui_cursor_x = 0; /* position of cursor in cursor mode */ +int gui_cursor_y = 0; /* position of cursor in cursor mode */ + + +/* + * gui_cursor_mode_toggle: toggle cursor mode + */ + +void +gui_cursor_mode_toggle () +{ + gui_cursor_mode ^= 1; + + if (gui_cursor_mode) + { + if (gui_cursor_debug) + gui_input_delete_line (gui_current_window->buffer); + gui_cursor_x = gui_window_cursor_x; + gui_cursor_y = gui_window_cursor_y; + gui_cursor_move_xy (0, 0); + } + else + { + /* restore input (and move cursor in input) */ + if (gui_cursor_debug) + gui_input_delete_line (gui_current_window->buffer); + gui_input_text_changed_modifier_and_signal (gui_current_window->buffer, 0); + gui_buffer_ask_chat_refresh (gui_current_window->buffer, 2); + } +} + +/* + * gui_cursor_debug_toggle: toggle debug for cursor mode + */ + +void +gui_cursor_debug_toggle () +{ + gui_cursor_debug ^= 1; + + if (gui_cursor_debug) + gui_chat_printf (NULL, _("Debug enabled for cursor mode")); + else + gui_chat_printf (NULL, _("Debug disabled for cursor mode")); +} + +/* + * gui_cursor_get_info: get info about what is pointed by cursor at (x,y) + */ + +void +gui_cursor_get_info (int x, int y, struct t_gui_cursor_info *cursor_info) +{ + cursor_info->x = x; + cursor_info->y = y; + + /* search window */ + cursor_info->window = gui_window_search_by_xy (x, y); + + /* chat area in this window? */ + if (cursor_info->window + && (x >= (cursor_info->window)->win_chat_x) + && (y >= (cursor_info->window)->win_chat_y) + && (x <= (cursor_info->window)->win_chat_x + (cursor_info->window)->win_chat_width - 1) + && (y <= (cursor_info->window)->win_chat_y + (cursor_info->window)->win_chat_height - 1)) + { + cursor_info->chat = 1; + } + else + cursor_info->chat = 0; + + /* search bar window, item, and line/col in item */ + gui_bar_window_search_by_xy (cursor_info->window, x, y, + &cursor_info->bar_window, + &cursor_info->bar_item, + &cursor_info->item_line, + &cursor_info->item_col); +} + +/* + * gui_cursor_display_debug_info: display debug info about (x,y) in input + */ + +void +gui_cursor_display_debug_info () +{ + struct t_gui_cursor_info cursor_info; + char str_info[1024]; + + if (!gui_cursor_debug) + return; + + gui_cursor_get_info (gui_cursor_x, gui_cursor_y, &cursor_info); + + snprintf (str_info, sizeof (str_info), + "%s(%d,%d) window:0x%lx (buffer: %s), chat: %d, " + "bar_window:0x%lx (bar: %s, item: %s, line: %d, col: %d)", + gui_color_get_custom ("yellow,red"), + cursor_info.x, cursor_info.y, + (long unsigned int)cursor_info.window, + (cursor_info.window) ? (cursor_info.window)->buffer->name : "-", + cursor_info.chat, + (long unsigned int)cursor_info.bar_window, + (cursor_info.bar_window) ? (cursor_info.bar_window)->bar->name : "-", + (cursor_info.bar_item) ? cursor_info.bar_item : "-", + cursor_info.item_line, + cursor_info.item_col); + gui_input_delete_line (gui_current_window->buffer); + gui_input_insert_string (gui_current_window->buffer, str_info, -1); +} + +/* + * gui_cursor_move_xy: set cursor at position (x,y) + */ + +void +gui_cursor_move_xy (int x, int y) +{ + if (!gui_cursor_mode) + gui_cursor_mode_toggle (); + + gui_cursor_x = x; + gui_cursor_y = y; + + if (gui_cursor_x < 0) + gui_cursor_x = 0; + else if (gui_cursor_x > gui_window_get_width () - 1) + gui_cursor_x = gui_window_get_width () - 1; + + if (gui_cursor_y < 0) + gui_cursor_y = 0; + else if (gui_cursor_y > gui_window_get_height () - 1) + gui_cursor_y = gui_window_get_height () - 1; + + gui_cursor_display_debug_info (); + gui_window_move_cursor (); +} + +/* + * gui_cursor_move_add_xy: move cursor by adding values to (x,y) + */ + +void +gui_cursor_move_add_xy (int add_x, int add_y) +{ + if (!gui_cursor_mode) + gui_cursor_mode_toggle (); + + gui_cursor_x += add_x; + gui_cursor_y += add_y; + + if (gui_cursor_x < 0) + gui_cursor_x = gui_window_get_width () - 1; + else if (gui_cursor_x > gui_window_get_width () - 1) + gui_cursor_x = 0; + + if (gui_cursor_y < 0) + gui_cursor_y = gui_window_get_height () - 1; + else if (gui_cursor_y > gui_window_get_height () - 1) + gui_cursor_y = 0; + + gui_cursor_display_debug_info (); + gui_window_move_cursor (); +} + +/* + * gui_cursor_move_area_add_xy: move cursor to another area by adding values to + * (x,y) + */ + +void +gui_cursor_move_area_add_xy (int add_x, int add_y) +{ + int x, y, width, height, area_found; + struct t_gui_cursor_info cursor_info_old, cursor_info_new; + + if (!gui_cursor_mode) + gui_cursor_mode_toggle (); + + area_found = 0; + + x = gui_cursor_x; + y = gui_cursor_y; + width = gui_window_get_width (); + height = gui_window_get_height (); + + gui_cursor_get_info (x, y, &cursor_info_old); + + if (add_x != 0) + x += add_x; + else + y += add_y; + + while ((x >= 0) && (x < width) && (y >= 0) && (y < height)) + { + gui_cursor_get_info (x, y, &cursor_info_new); + if (((cursor_info_new.window && cursor_info_new.chat) + || cursor_info_new.bar_window) + && ((cursor_info_old.window != cursor_info_new.window) + || (cursor_info_old.bar_window != cursor_info_new.bar_window))) + { + area_found = 1; + break; + } + + if (add_x != 0) + x += add_x; + else + y += add_y; + } + + if (area_found) + { + if (cursor_info_new.window && cursor_info_new.chat) + { + x = (cursor_info_new.window)->win_chat_x; + y = (cursor_info_new.window)->win_chat_y; + } + else if (cursor_info_new.bar_window) + { + x = (cursor_info_new.bar_window)->x; + y = (cursor_info_new.bar_window)->y; + } + else + area_found = 0; + } + + if (area_found) + { + gui_cursor_x = x; + gui_cursor_y = y; + gui_cursor_display_debug_info (); + gui_window_move_cursor (); + } +} + +/* + * gui_cursor_move_area: move cursor to another area by name + */ + +void +gui_cursor_move_area (const char *area) +{ + int area_found, x, y; + struct t_gui_bar_window *ptr_bar_win; + struct t_gui_bar *ptr_bar; + + area_found = 0; + x = 0; + y = 0; + + if (strcmp (area, "chat") == 0) + { + area_found = 1; + x = gui_current_window->win_chat_x; + y = gui_current_window->win_chat_y; + } + else + { + for (ptr_bar_win = gui_current_window->bar_windows; ptr_bar_win; + ptr_bar_win = ptr_bar_win->next_bar_window) + { + if (strcmp (ptr_bar_win->bar->name, area) == 0) + { + area_found = 1; + x = ptr_bar_win->x; + y = ptr_bar_win->y; + break; + } + } + if (!area_found) + { + for (ptr_bar = gui_bars; ptr_bar; ptr_bar = ptr_bar->next_bar) + { + if (ptr_bar->bar_window && (strcmp (ptr_bar->name, area) == 0)) + { + area_found = 1; + x = ptr_bar->bar_window->x; + y = ptr_bar->bar_window->y; + } + } + } + } + + if (area_found) + { + if (!gui_cursor_mode) + gui_cursor_mode_toggle (); + gui_cursor_x = x; + gui_cursor_y = y; + gui_cursor_display_debug_info (); + gui_window_move_cursor (); + } +} diff --git a/src/gui/gui-cursor.h b/src/gui/gui-cursor.h new file mode 100644 index 000000000..b27b8f4eb --- /dev/null +++ b/src/gui/gui-cursor.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_GUI_CURSOR_H +#define __WEECHAT_GUI_CURSOR_H 1 + +/* cursor structures */ + +struct t_gui_cursor_info +{ + int x, y; /* (x,y) on screen */ + struct t_gui_window *window; /* window found */ + int chat; /* 1 for chat area, otherwise 0 */ + struct t_gui_bar_window *bar_window; /* bar window found */ + char *bar_item; /* bar item found */ + int item_line; /* line in bar item */ + int item_col; /* column in bar item */ +}; + +/* cursor variables */ + +extern int gui_cursor_mode; +extern int gui_cursor_debug; +extern int gui_cursor_x; +extern int gui_cursor_y; + +/* cursor functions */ + +extern void gui_cursor_mode_toggle (); +extern void gui_cursor_debug_toggle (); +extern void gui_cursor_get_info (int x, int y, + struct t_gui_cursor_info *cursor_info); +extern void gui_cursor_move_xy (int x, int y); +extern void gui_cursor_move_add_xy (int add_x, int add_y); +extern void gui_cursor_move_area_add_xy (int add_x, int add_y); +extern void gui_cursor_move_area (const char *area); + +#endif /* __WEECHAT_GUI_CURSOR_H */ diff --git a/src/gui/gui-input.c b/src/gui/gui-input.c index 7828e77a9..aa5c5dc5a 100644 --- a/src/gui/gui-input.c +++ b/src/gui/gui-input.c @@ -38,6 +38,7 @@ #include "gui-input.h" #include "gui-buffer.h" #include "gui-completion.h" +#include "gui-cursor.h" #include "gui-history.h" #include "gui-hotlist.h" #include "gui-key.h" @@ -117,26 +118,29 @@ gui_input_text_changed_modifier_and_signal (struct t_gui_buffer *buffer, { char str_buffer[128], *new_input; - if (save_undo) - gui_buffer_undo_add (buffer); - - /* send modifier, and change input if needed */ - snprintf (str_buffer, sizeof (str_buffer), - "0x%lx", (long unsigned int)buffer); - new_input = hook_modifier_exec (NULL, - "input_text_content", - str_buffer, - (buffer->input_buffer) ? - buffer->input_buffer : ""); - if (new_input) + if (!gui_cursor_mode) { - if (!buffer->input_buffer - || strcmp (new_input, buffer->input_buffer) != 0) + if (save_undo) + gui_buffer_undo_add (buffer); + + /* send modifier, and change input if needed */ + snprintf (str_buffer, sizeof (str_buffer), + "0x%lx", (long unsigned int)buffer); + new_input = hook_modifier_exec (NULL, + "input_text_content", + str_buffer, + (buffer->input_buffer) ? + buffer->input_buffer : ""); + if (new_input) { - /* input has been changed by modifier, use it */ - gui_input_replace_input (buffer, new_input); + if (!buffer->input_buffer + || strcmp (new_input, buffer->input_buffer) != 0) + { + /* input has been changed by modifier, use it */ + gui_input_replace_input (buffer, new_input); + } + free (new_input); } - free (new_input); } /* send signal */ @@ -1339,10 +1343,10 @@ gui_input_hotlist_clear (struct t_gui_buffer *buffer) */ void -gui_input_grab_key (struct t_gui_buffer *buffer) +gui_input_grab_key (struct t_gui_buffer *buffer, const char *delay) { if (buffer->input) - gui_key_grab_init (0); + gui_key_grab_init (0, delay); } /* @@ -1351,10 +1355,10 @@ gui_input_grab_key (struct t_gui_buffer *buffer) */ void -gui_input_grab_key_command (struct t_gui_buffer *buffer) +gui_input_grab_key_command (struct t_gui_buffer *buffer, const char *delay) { if (buffer->input) - gui_key_grab_init (1); + gui_key_grab_init (1, delay); } /* diff --git a/src/gui/gui-input.h b/src/gui/gui-input.h index dbad22b7a..89a919baa 100644 --- a/src/gui/gui-input.h +++ b/src/gui/gui-input.h @@ -70,8 +70,10 @@ extern void gui_input_jump_last_buffer (struct t_gui_buffer *buffer); extern void gui_input_jump_previously_visited_buffer (struct t_gui_buffer *buffer); extern void gui_input_jump_next_visited_buffer (struct t_gui_buffer *buffer); extern void gui_input_hotlist_clear (struct t_gui_buffer *buffer); -extern void gui_input_grab_key (struct t_gui_buffer *buffer); -extern void gui_input_grab_key_command (struct t_gui_buffer *buffer); +extern void gui_input_grab_key (struct t_gui_buffer *buffer, + const char *delay); +extern void gui_input_grab_key_command (struct t_gui_buffer *buffer, + const char *delay); extern void gui_input_scroll_unread (struct t_gui_buffer *buffer); extern void gui_input_set_unread (); extern void gui_input_set_unread_current (struct t_gui_buffer *buffer); diff --git a/src/gui/gui-key.c b/src/gui/gui-key.c index 30d40d65f..7bf4ccb6f 100644 --- a/src/gui/gui-key.c +++ b/src/gui/gui-key.c @@ -32,6 +32,7 @@ #include <time.h> #include "../core/weechat.h" +#include "../core/wee-hashtable.h" #include "../core/wee-hdata.h" #include "../core/wee-hook.h" #include "../core/wee-infolist.h" @@ -41,11 +42,15 @@ #include "../core/wee-utf8.h" #include "../plugins/plugin.h" #include "gui-key.h" +#include "gui-bar.h" +#include "gui-bar-window.h" #include "gui-buffer.h" #include "gui-chat.h" #include "gui-color.h" #include "gui-completion.h" +#include "gui-cursor.h" #include "gui-input.h" +#include "gui-mouse.h" #include "gui-window.h" @@ -57,14 +62,15 @@ int gui_keys_count[GUI_KEY_NUM_CONTEXTS]; /* keys number */ int gui_default_keys_count[GUI_KEY_NUM_CONTEXTS]; /* default keys number */ char *gui_key_context_string[GUI_KEY_NUM_CONTEXTS] = -{ "default", "search" }; +{ "default", "search", "cursor", "mouse" }; int gui_key_verbose = 0; /* 1 to see some messages */ -char gui_key_combo_buffer[128]; /* buffer used for combos */ +char gui_key_combo_buffer[256]; /* buffer used for combos */ int gui_key_grab = 0; /* 1 if grab mode enabled (alt-k) */ int gui_key_grab_count = 0; /* number of keys pressed in grab mode */ int gui_key_grab_command = 0; /* grab command bound to key? */ +int gui_key_grab_delay = 0; /* delay for grab (default is 500) */ int *gui_key_buffer = NULL; /* input buffer (for paste detection) */ int gui_key_buffer_alloc = 0; /* input buffer allocated size */ @@ -136,6 +142,9 @@ gui_key_search_context (const char *context) int gui_key_get_current_context () { + if (gui_cursor_mode) + return GUI_KEY_CONTEXT_CURSOR; + if (gui_current_window && (gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED)) return GUI_KEY_CONTEXT_SEARCH; @@ -148,24 +157,44 @@ gui_key_get_current_context () */ void -gui_key_grab_init (int grab_command) +gui_key_grab_init (int grab_command, const char *delay) { + long milliseconds; + char *error; + gui_key_grab = 1; gui_key_grab_count = 0; gui_key_grab_command = grab_command; + + gui_key_grab_delay = GUI_KEY_GRAB_DELAY_DEFAULT; + if (delay != NULL) + { + error = NULL; + milliseconds = strtol (delay, &error, 10); + if (error && !error[0] && (milliseconds >= 0)) + { + gui_key_grab_delay = milliseconds; + if (gui_key_grab_delay == 0) + gui_key_grab_delay = 1; + } + } } /* - * gui_key_grab_end: insert grabbed key in input buffer + * gui_key_grab_end_timer_cb: insert grabbed key in input buffer */ -void -gui_key_grab_end () +int +gui_key_grab_end_timer_cb (void *data, int remaining_calls) { char *expanded_key; struct t_gui_key *ptr_key; - /* get expanded name (for example: ^U => ctrl-u) */ + /* make C compiler happy */ + (void) data; + (void) remaining_calls; + + /* get expanded name (for example: \x01+U => ctrl-u) */ expanded_key = gui_key_get_expanded_name (gui_key_combo_buffer); if (expanded_key) @@ -195,11 +224,13 @@ gui_key_grab_end () gui_key_grab_count = 0; gui_key_grab_command = 0; gui_key_combo_buffer[0] = '\0'; + + return WEECHAT_RC_OK; } /* * gui_key_get_internal_code: get internal code from user key name - * for example: return "^R" for "ctrl-R" + * for example: return "\x01+R" for "ctrl-R" */ char * @@ -214,17 +245,17 @@ gui_key_get_internal_code (const char *key) { if (strncmp (key, "meta2-", 6) == 0) { - strcat (result, "^[["); + strcat (result, "\x01[["); key += 6; } if (strncmp (key, "meta-", 5) == 0) { - strcat (result, "^["); + strcat (result, "\x01["); key += 5; } else if (strncmp (key, "ctrl-", 5) == 0) { - strcat (result, "^"); + strcat (result, "\x01"); key += 5; } else @@ -242,7 +273,7 @@ gui_key_get_internal_code (const char *key) /* * gui_key_get_expanded_name: get expanded name from internal key code - * for example: return "ctrl-R" for "^R" + * for example: return "ctrl-R" for "\x01+R" */ char * @@ -259,17 +290,17 @@ gui_key_get_expanded_name (const char *key) result[0] = '\0'; while (key[0]) { - if (strncmp (key, "^[[", 3) == 0) + if (strncmp (key, "\x01[[", 3) == 0) { strcat (result, "meta2-"); key += 3; } - if (strncmp (key, "^[", 2) == 0) + if (strncmp (key, "\x01[", 2) == 0) { strcat (result, "meta-"); key += 2; } - else if ((key[0] == '^') && (key[1])) + else if ((key[0] == '\x01') && (key[1])) { strcat (result, "ctrl-"); key++; @@ -403,8 +434,10 @@ gui_key_new (struct t_gui_buffer *buffer, int context, const char *key, if (gui_key_verbose) { - gui_chat_printf (NULL, - _("New key binding: %s%s => %s%s"), + gui_chat_printf (gui_current_window->buffer, + _("New key binding (context \"%s\"): " + "%s%s => %s%s"), + gui_key_context_string[context], (expanded_name) ? expanded_name : new_key->key, GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), GUI_COLOR(GUI_COLOR_CHAT), @@ -443,10 +476,13 @@ gui_key_search (struct t_gui_key *keys, const char *key) */ int -gui_key_cmp (const char *key, const char *search) +gui_key_cmp (const char *key, const char *search, int context) { int diff; + if (context == GUI_KEY_CONTEXT_MOUSE) + return strcmp (key, search); + while (search[0]) { diff = utf8_charcmp (key, search); @@ -472,8 +508,14 @@ gui_key_search_part (struct t_gui_buffer *buffer, int context, for (ptr_key = (buffer) ? buffer->keys : gui_keys[context]; ptr_key; ptr_key = ptr_key->next_key) { - if (ptr_key->key && (gui_key_cmp (ptr_key->key, key) == 0)) - return ptr_key; + if (ptr_key->key + && (((context != GUI_KEY_CONTEXT_CURSOR) + && (context != GUI_KEY_CONTEXT_MOUSE)) + || (ptr_key->key[0] != '@'))) + { + if (gui_key_cmp (ptr_key->key, key, context) == 0) + return ptr_key; + } } /* key not found */ @@ -552,6 +594,173 @@ gui_key_unbind (struct t_gui_buffer *buffer, int context, const char *key, } /* + * gui_key_focus_matching: return 1 if area in key is matching focus area on + * screen (cursor/mouse) + */ + +int +gui_key_focus_matching (const char *key, + struct t_gui_cursor_info *cursor_info) +{ + int match, area_chat; + char *area_bar, *area_item, *pos; + + if (key[1] == '*') + return 1; + + match = 0; + + pos = strchr (key, ':'); + if (pos) + { + area_chat = 0; + area_bar = NULL; + area_item = NULL; + if (strncmp (key + 1, "chat:", 5) == 0) + area_chat = 1; + else if (strncmp (key + 1, "bar(", 4) == 0) + { + area_bar = string_strndup (key + 5, pos - key - 6); + } + else if (strncmp (key + 1, "item(", 5) == 0) + { + area_item = string_strndup (key + 6, pos - key - 7); + } + if (area_chat || area_bar || area_item) + { + if (area_chat && cursor_info->chat) + { + match = 1; + } + else if (area_bar && cursor_info->bar_window + && ((strcmp (area_bar, "*") == 0) + || (strcmp (area_bar, (cursor_info->bar_window)->bar->name) == 0))) + { + match = 1; + } + else if (area_item && cursor_info->bar_item + && ((strcmp (area_item, "*") == 0) + || (strcmp (area_item, cursor_info->bar_item) == 0))) + { + match = 1; + } + } + + if (area_bar) + free (area_bar); + if (area_item) + free (area_item); + } + + return match; +} + +/* + * gui_key_focus_command: run command according to focus + * return 1 if a command was executed, otherwise 0 + */ + +int +gui_key_focus_command (const char *key, int context, + int focus_specific, int focus_any, + struct t_gui_cursor_info *cursor_info) +{ + struct t_gui_key *ptr_key; + int i, errors; + char *pos, *pos_joker, *command, **commands; + struct t_hashtable *hashtable; + + for (ptr_key = gui_keys[context]; ptr_key; + ptr_key = ptr_key->next_key) + { + if (ptr_key->key && (ptr_key->key[0] == '@')) + { + pos = strchr (ptr_key->key, ':'); + if (pos) + { + pos_joker = strchr (ptr_key->key, '*'); + if (!focus_specific && (!pos_joker || (pos_joker > pos))) + continue; + if (!focus_any && pos_joker && (pos_joker < pos)) + continue; + + pos++; + if (gui_key_cmp (pos, key, context) == 0) + { + if (gui_key_focus_matching (ptr_key->key, cursor_info)) + { + hashtable = hook_focus_get_data (cursor_info); + if (gui_mouse_debug) + { + gui_chat_printf (NULL, "Hashtable focus: %s", + hashtable_get_string (hashtable, + "keys_values")); + } + command = string_replace_with_hashtable (ptr_key->command, + hashtable, + &errors); + if (command) + { + if (errors == 0) + { + if ((context == GUI_KEY_CONTEXT_CURSOR) + && gui_cursor_debug) + { + gui_input_delete_line (gui_current_window->buffer); + } + commands = string_split_command (command, + ';'); + if (commands) + { + for (i = 0; commands[i]; i++) + { + input_data (gui_current_window->buffer, commands[i]); + } + string_free_split_command (commands); + } + } + free (command); + } + if (hashtable) + hashtable_free (hashtable); + return 1; + } + } + } + } + } + + return 0; +} + +/* + * gui_key_focus: treat key pressed in cursor or mouse mode, + * looking for keys: "{area}key" in context "cursor" or "mouse" + * return 1 if a command was executed, otherwise 0 + */ + +int +gui_key_focus (const char *key, int context) +{ + struct t_gui_cursor_info cursor_info; + + if (context == GUI_KEY_CONTEXT_MOUSE) + { + gui_cursor_get_info (gui_mouse_event_x[0], gui_mouse_event_y[0], + &cursor_info); + } + else + { + gui_cursor_get_info (gui_cursor_x, gui_cursor_y, &cursor_info); + } + + if (gui_key_focus_command (key, context, 1, 0, &cursor_info)) + return 1; + + return gui_key_focus_command (key, context, 0, 1, &cursor_info); +} + +/* * gui_key_pressed: treat new key pressed * return: 1 if key should be added to input buffer * 0 otherwise @@ -560,22 +769,52 @@ gui_key_unbind (struct t_gui_buffer *buffer, int context, const char *key, int gui_key_pressed (const char *key_str) { - int first_key, context; + int i, first_key, context, length, length_key; struct t_gui_key *ptr_key; - char *buffer_before_key; - char **commands, **ptr_cmd; + char **commands; + const char *mouse_key; /* add key to buffer */ first_key = (gui_key_combo_buffer[0] == '\0'); - strcat (gui_key_combo_buffer, key_str); + length = strlen (gui_key_combo_buffer); + length_key = strlen (key_str); + if (length + length_key + 1 <= (int)sizeof (gui_key_combo_buffer)) + strcat (gui_key_combo_buffer, key_str); /* if we are in "show mode", increase counter and return */ if (gui_key_grab) { + if (gui_key_grab_count == 0) + { + hook_timer (NULL, gui_key_grab_delay, 0, 1, + &gui_key_grab_end_timer_cb, NULL); + } gui_key_grab_count++; return 0; } + /* mode "mouse grab" (mouse event pending) */ + if (gui_mouse_grab) + { + mouse_key = gui_mouse_grab_code2key (gui_key_combo_buffer); + if (mouse_key) + { + gui_key_combo_buffer[0] = '\0'; + strcat (gui_key_combo_buffer, mouse_key); + gui_mouse_grab_end (); + if (gui_key_combo_buffer[0]) + { + (void) gui_key_focus (gui_key_combo_buffer, + GUI_KEY_CONTEXT_MOUSE); + gui_key_combo_buffer[0] = '\0'; + gui_mouse_reset_event (); + } + } + return 0; + } + + ptr_key = NULL; + context = gui_key_get_current_context (); switch (context) { @@ -601,6 +840,11 @@ gui_key_pressed (const char *key_str) gui_key_combo_buffer); } break; + case GUI_KEY_CONTEXT_CURSOR: + ptr_key = gui_key_search_part (NULL, + GUI_KEY_CONTEXT_CURSOR, + gui_key_combo_buffer); + break; } /* if key is found, then execute action */ @@ -609,29 +853,30 @@ gui_key_pressed (const char *key_str) if (strcmp (ptr_key->key, gui_key_combo_buffer) == 0) { /* exact combo found => execute function or command */ - buffer_before_key = - (gui_current_window->buffer->input_buffer) ? - strdup (gui_current_window->buffer->input_buffer) : strdup (""); gui_key_combo_buffer[0] = '\0'; if (ptr_key->command) { commands = string_split_command (ptr_key->command, ';'); if (commands) { - for (ptr_cmd = commands; *ptr_cmd; ptr_cmd++) + for (i = 0; commands[i]; i++) { - input_data (gui_current_window->buffer, - *ptr_cmd); + input_data (gui_current_window->buffer, commands[i]); } string_free_split_command (commands); } } - - if (buffer_before_key) - free (buffer_before_key); } return 0; } + else if (context == GUI_KEY_CONTEXT_CURSOR) + { + if (gui_key_focus (gui_key_combo_buffer, GUI_KEY_CONTEXT_CURSOR)) + { + gui_key_combo_buffer[0] = '\0'; + return 0; + } + } gui_key_combo_buffer[0] = '\0'; @@ -829,6 +1074,8 @@ struct t_hdata * gui_key_hdata_key_cb (void *data, const char *hdata_name) { struct t_hdata *hdata; + int i; + char str_list[128]; /* make C compiler happy */ (void) data; @@ -840,10 +1087,29 @@ gui_key_hdata_key_cb (void *data, const char *hdata_name) HDATA_VAR(struct t_gui_key, command, STRING, NULL); HDATA_VAR(struct t_gui_key, prev_key, POINTER, hdata_name); HDATA_VAR(struct t_gui_key, next_key, POINTER, hdata_name); - HDATA_LIST(gui_keys); - HDATA_LIST(last_gui_key); - HDATA_LIST(gui_default_keys); - HDATA_LIST(last_gui_default_key); + for (i = 0; i < GUI_KEY_NUM_CONTEXTS; i++) + { + snprintf (str_list, sizeof (str_list), + "gui_keys%s%s", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : "_", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : gui_key_context_string[i]); + hdata_new_list(hdata, str_list, &gui_keys[i]); + snprintf (str_list, sizeof (str_list), + "last_gui_key%s%s", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : "_", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : gui_key_context_string[i]); + hdata_new_list(hdata, str_list, &last_gui_key[i]); + snprintf (str_list, sizeof (str_list), + "gui_default_keys%s%s", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : "_", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : gui_key_context_string[i]); + hdata_new_list(hdata, str_list, &gui_default_keys[i]); + snprintf (str_list, sizeof (str_list), + "last_gui_default_key%s%s", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : "_", + (i == GUI_KEY_CONTEXT_DEFAULT) ? "" : gui_key_context_string[i]); + hdata_new_list(hdata, str_list, &last_gui_default_key[i]); + } } return hdata; } diff --git a/src/gui/gui-key.h b/src/gui/gui-key.h index 32e3f0482..d05ef7391 100644 --- a/src/gui/gui-key.h +++ b/src/gui/gui-key.h @@ -22,10 +22,14 @@ #define GUI_KEY_BUFFER_BLOCK_SIZE 256 +#define GUI_KEY_GRAB_DELAY_DEFAULT 500 + enum t_gui_key_context { GUI_KEY_CONTEXT_DEFAULT = 0, GUI_KEY_CONTEXT_SEARCH, + GUI_KEY_CONTEXT_CURSOR, + GUI_KEY_CONTEXT_MOUSE, /* number of key contexts */ GUI_KEY_NUM_CONTEXTS, }; @@ -62,8 +66,7 @@ extern time_t gui_key_last_activity_time; extern void gui_key_init (); extern int gui_key_search_context (const char *context); -extern void gui_key_grab_init (int grab_command); -extern void gui_key_grab_end (); +extern void gui_key_grab_init (int grab_command, const char *delay); extern char *gui_key_get_internal_code (const char *key); extern char *gui_key_get_expanded_name (const char *key); extern struct t_gui_key *gui_key_new (struct t_gui_buffer *buffer, diff --git a/src/gui/gui-mouse.c b/src/gui/gui-mouse.c new file mode 100644 index 000000000..81fc9ffd3 --- /dev/null +++ b/src/gui/gui-mouse.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * gui-mouse.c: functions for mouse (used by all GUI) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "../core/weechat.h" +#include "gui-chat.h" + + +int gui_mouse_enabled = 0; /* 1 if mouse support is enabled */ +int gui_mouse_debug = 0; /* debug mode for mouse */ +int gui_mouse_grab = 0; /* 1 if grab mouse code enabled */ +int gui_mouse_event_index = 0; /* index for x/y in array (0 or 1) */ +int gui_mouse_event_x[2] = { 0, 0 }; /* position of latest mouse event: */ + /* (on click, on release) */ +int gui_mouse_event_y[2] = { 0, 0 }; /* position of latest mouse event */ + /* (on click, on release) */ +char gui_mouse_event_button = '#'; /* button pressed (or wheel) */ + + +/* + * gui_mouse_debug_toggle: toggle debug for mouse events + */ + +void +gui_mouse_debug_toggle () +{ + gui_mouse_debug ^= 1; + + if (gui_mouse_debug) + gui_chat_printf (NULL, _("Debug enabled for mouse")); + else + gui_chat_printf (NULL, _("Debug disabled for mouse")); +} + +/* + * gui_mouse_reset_event: reset event values + */ + +void +gui_mouse_reset_event () +{ + gui_mouse_event_index = 0; + gui_mouse_event_x[0] = 0; + gui_mouse_event_y[0] = 0; + gui_mouse_event_x[1] = 0; + gui_mouse_event_y[1] = 0; + gui_mouse_event_button = '#'; +} diff --git a/src/gui/gui-mouse.h b/src/gui/gui-mouse.h new file mode 100644 index 000000000..a579655f8 --- /dev/null +++ b/src/gui/gui-mouse.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_GUI_MOUSE_H +#define __WEECHAT_GUI_MOUSE_H 1 + +/* mouse variables */ + +extern int gui_mouse_enabled; +extern int gui_mouse_debug; +extern int gui_mouse_grab; +extern int gui_mouse_event_index; +extern int gui_mouse_event_x[2]; +extern int gui_mouse_event_y[2]; +extern char gui_mouse_event_button; + +/* mouse functions */ + +extern void gui_mouse_debug_toggle (); +extern void gui_mouse_reset_event (); + +/* mouse functions (GUI dependent) */ + +extern void gui_mouse_enable (); +extern void gui_mouse_disable (); +extern void gui_mouse_display_state (); +extern void gui_mouse_grab_init (); +extern const char *gui_mouse_grab_code2key (const char *code); +extern void gui_mouse_grab_end (); + +#endif /* __WEECHAT_GUI_MOUSE_H */ diff --git a/src/gui/gui-window.c b/src/gui/gui-window.c index bb22d1297..34102870e 100644 --- a/src/gui/gui-window.c +++ b/src/gui/gui-window.c @@ -70,9 +70,36 @@ struct t_gui_layout_window *gui_window_layout_before_zoom = NULL; /* layout before zooming on a window */ int gui_window_layout_id_current_window = -1; /* current window id before zoom */ +int gui_window_cursor_x = 0; /* cursor pos on screen */ +int gui_window_cursor_y = 0; /* cursor pos on screen */ /* + * gui_window_search_by_xy: get pointer of window displayed at (x,y) + * return NULL if no window is found + */ + +struct t_gui_window * +gui_window_search_by_xy (int x, int y) +{ + struct t_gui_window *ptr_window; + + for (ptr_window = gui_windows; ptr_window; + ptr_window = ptr_window->next_window) + { + if ((x >= ptr_window->win_x) && (y >= ptr_window->win_y) + && (x <= ptr_window->win_x + ptr_window->win_width - 1) + && (y <= ptr_window->win_y + ptr_window->win_height - 1)) + { + return ptr_window; + } + } + + /* no window at this location */ + return NULL; +} + +/* * gui_window_ask_refresh: set "gui_window_refresh_needed" flag */ @@ -1293,8 +1320,8 @@ gui_window_hdata_window_cb (void *data, const char *hdata_name) HDATA_VAR(struct t_gui_window, win_chat_height, INTEGER, NULL); HDATA_VAR(struct t_gui_window, win_chat_cursor_x, INTEGER, NULL); HDATA_VAR(struct t_gui_window, win_chat_cursor_y, INTEGER, NULL); - HDATA_VAR(struct t_gui_window, bar_windows, POINTER, NULL); - HDATA_VAR(struct t_gui_window, last_bar_window, POINTER, NULL); + HDATA_VAR(struct t_gui_window, bar_windows, POINTER, "bar_window"); + HDATA_VAR(struct t_gui_window, last_bar_window, POINTER, "bar_window"); HDATA_VAR(struct t_gui_window, refresh_needed, INTEGER, NULL); HDATA_VAR(struct t_gui_window, gui_objects, POINTER, NULL); HDATA_VAR(struct t_gui_window, buffer, POINTER, "buffer"); diff --git a/src/gui/gui-window.h b/src/gui/gui-window.h index 92b76a517..9bb76623a 100644 --- a/src/gui/gui-window.h +++ b/src/gui/gui-window.h @@ -27,10 +27,12 @@ #define GUI_WINDOW_CHAT_MIN_HEIGHT 2 struct t_infolist; +struct t_gui_bar_window; extern int gui_init_ok; extern int gui_ok; extern int gui_window_refresh_needed; +extern int gui_window_cursor_x, gui_window_cursor_y; /* window structures */ @@ -116,6 +118,8 @@ extern struct t_gui_window *gui_current_window; extern struct t_gui_window_tree *gui_windows_tree; /* window functions */ + +extern struct t_gui_window *gui_window_search_by_xy (int x, int y); extern void gui_window_ask_refresh (int refresh); extern int gui_window_tree_init (struct t_gui_window *window); extern void gui_window_tree_node_to_leaf (struct t_gui_window_tree *node, @@ -200,6 +204,7 @@ extern int gui_window_balance (struct t_gui_window_tree *tree); extern void gui_window_swap (struct t_gui_window *window, int direction); extern void gui_window_refresh_screen (int full_refresh); extern void gui_window_set_title (const char *title); +extern void gui_window_move_cursor (); extern void gui_window_term_display_infos (); extern void gui_window_objects_print_log (struct t_gui_window *window); diff --git a/src/plugins/irc/irc-bar-item.c b/src/plugins/irc/irc-bar-item.c index e6e24e682..89b50392c 100644 --- a/src/plugins/irc/irc-bar-item.c +++ b/src/plugins/irc/irc-bar-item.c @@ -493,6 +493,49 @@ irc_bar_item_input_prompt (void *data, struct t_gui_bar_item *item, } /* + * irc_bar_item_focus_buffer_nicklist: focus on nicklist + */ + +struct t_hashtable * +irc_bar_item_focus_buffer_nicklist (void *data, + struct t_hashtable *info) +{ + long unsigned int value; + int rc; + struct t_gui_buffer *buffer; + struct t_irc_nick *ptr_nick; + const char *str_buffer, *nick; + + str_buffer = weechat_hashtable_get (info, "_buffer"); + rc = sscanf (str_buffer, "%lx", &value); + if ((rc == EOF) || (rc == 0)) + return NULL; + + buffer = (struct t_gui_buffer *)value; + + IRC_BUFFER_GET_SERVER_CHANNEL(buffer); + + /* make C compiler happy */ + (void) data; + + if (ptr_channel) + { + nick = weechat_hashtable_get (info, "nick"); + if (nick) + { + ptr_nick = irc_nick_search (ptr_channel, nick); + if (ptr_nick && ptr_nick->host) + { + weechat_hashtable_set (info, "host", ptr_nick->host); + return info; + } + } + } + + return NULL; +} + +/* * irc_bar_item_init: initialize IRC bar items */ @@ -506,4 +549,6 @@ irc_bar_item_init () weechat_bar_item_new ("irc_channel", &irc_bar_item_channel, NULL); weechat_bar_item_new ("lag", &irc_bar_item_lag, NULL); weechat_bar_item_new ("input_prompt", &irc_bar_item_input_prompt, NULL); + weechat_hook_focus ("500|buffer_nicklist", + &irc_bar_item_focus_buffer_nicklist, NULL); } diff --git a/src/plugins/plugin-api.c b/src/plugins/plugin-api.c index 7e3861541..b54b2ab2d 100644 --- a/src/plugins/plugin-api.c +++ b/src/plugins/plugin-api.c @@ -50,6 +50,7 @@ #include "../gui/gui-chat.h" #include "../gui/gui-completion.h" #include "../gui/gui-color.h" +#include "../gui/gui-cursor.h" #include "../gui/gui-filter.h" #include "../gui/gui-history.h" #include "../gui/gui-hotlist.h" @@ -365,6 +366,11 @@ plugin_api_info_get_internal (void *data, const char *info_name, snprintf (value, sizeof (value), "%d", gui_filters_enabled); return value; } + else if (string_strcasecmp (info_name, "cursor_mode") == 0) + { + snprintf (value, sizeof (value), "%d", gui_cursor_mode); + return value; + } /* info not found */ return NULL; @@ -997,6 +1003,8 @@ plugin_api_init () &plugin_api_info_get_internal, NULL); hook_info (NULL, "filters_enabled", N_("1 if filters are enabled"), NULL, &plugin_api_info_get_internal, NULL); + hook_info (NULL, "cursor_mode", N_("1 if cursor mode is enabled"), NULL, + &plugin_api_info_get_internal, NULL); /* WeeChat core infolist hooks */ hook_infolist (NULL, "bar", N_("list of bars"), @@ -1064,6 +1072,8 @@ plugin_api_init () &gui_bar_hdata_bar_cb, NULL); hook_hdata (NULL, "bar_item", N_("bar item"), &gui_bar_item_hdata_bar_item_cb, NULL); + hook_hdata (NULL, "bar_window", N_("bar window"), + &gui_bar_window_hdata_bar_window_cb, NULL); hook_hdata (NULL, "buffer", N_("buffer"), &gui_buffer_hdata_buffer_cb, NULL); hook_hdata (NULL, "completion", N_("structure with completion"), diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 79bf76039..c785d3c46 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -607,6 +607,7 @@ plugin_load (const char *filename) new_plugin->hook_info_hashtable = &hook_info_hashtable; new_plugin->hook_infolist = &hook_infolist; new_plugin->hook_hdata = &hook_hdata; + new_plugin->hook_focus = &hook_focus; new_plugin->unhook = &unhook; new_plugin->unhook_all = &unhook_all_plugin; diff --git a/src/plugins/scripts/lua/weechat-lua-api.c b/src/plugins/scripts/lua/weechat-lua-api.c index ccdba77ad..fe6ecaccc 100644 --- a/src/plugins/scripts/lua/weechat-lua-api.c +++ b/src/plugins/scripts/lua/weechat-lua-api.c @@ -4693,6 +4693,76 @@ weechat_lua_api_hook_infolist (lua_State *L) } /* + * weechat_lua_api_hook_focus_cb: callback for focus hooked + */ + +struct t_hashtable * +weechat_lua_api_hook_focus_cb (void *data, + struct t_hashtable *info) +{ + struct t_script_callback *script_callback; + void *lua_argv[2]; + char empty_arg[1] = { '\0' }; + + script_callback = (struct t_script_callback *)data; + + if (script_callback && script_callback->function && script_callback->function[0]) + { + lua_argv[0] = (script_callback->data) ? script_callback->data : empty_arg; + lua_argv[1] = info; + + return (struct t_hashtable *)weechat_lua_exec (script_callback->script, + WEECHAT_SCRIPT_EXEC_HASHTABLE, + script_callback->function, + "sh", lua_argv); + } + + return NULL; +} + +/* + * weechat_lua_api_hook_focus: hook a focus + */ + +static int +weechat_lua_api_hook_focus (lua_State *L) +{ + const char *area, *function, *data; + char *result; + int n; + + /* make C compiler happy */ + (void) L; + + if (!lua_current_script || !lua_current_script->name) + { + WEECHAT_SCRIPT_MSG_NOT_INIT(LUA_CURRENT_SCRIPT_NAME, "hook_focus"); + LUA_RETURN_EMPTY; + } + + n = lua_gettop (lua_current_interpreter); + + if (n < 3) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGS(LUA_CURRENT_SCRIPT_NAME, "hook_focus"); + LUA_RETURN_EMPTY; + } + + area = lua_tostring (lua_current_interpreter, -3); + function = lua_tostring (lua_current_interpreter, -2); + data = lua_tostring (lua_current_interpreter, -1); + + result = script_ptr2str (script_api_hook_focus (weechat_lua_plugin, + lua_current_script, + area, + &weechat_lua_api_hook_focus_cb, + function, + data)); + + LUA_RETURN_STRING_FREE(result); +} + +/* * weechat_lua_api_unhook: unhook something */ @@ -8322,6 +8392,7 @@ const struct luaL_reg weechat_lua_api_funcs[] = { { "hook_info", &weechat_lua_api_hook_info }, { "hook_info_hashtable", &weechat_lua_api_hook_info_hashtable }, { "hook_infolist", &weechat_lua_api_hook_infolist }, + { "hook_focus", &weechat_lua_api_hook_focus }, { "unhook", &weechat_lua_api_unhook }, { "unhook_all", &weechat_lua_api_unhook_all }, { "buffer_new", &weechat_lua_api_buffer_new }, diff --git a/src/plugins/scripts/perl/weechat-perl-api.c b/src/plugins/scripts/perl/weechat-perl-api.c index 9fb575b99..45429dbbc 100644 --- a/src/plugins/scripts/perl/weechat-perl-api.c +++ b/src/plugins/scripts/perl/weechat-perl-api.c @@ -4267,6 +4267,72 @@ XS (XS_weechat_api_hook_infolist) } /* + * weechat_perl_api_hook_focus_cb: callback for focus hooked + */ + +struct t_hashtable * +weechat_perl_api_hook_focus_cb (void *data, + struct t_hashtable *info) +{ + struct t_script_callback *script_callback; + void *perl_argv[2]; + char empty_arg[1] = { '\0' }; + + script_callback = (struct t_script_callback *)data; + + if (script_callback && script_callback->function && script_callback->function[0]) + { + perl_argv[0] = (script_callback->data) ? script_callback->data : empty_arg; + perl_argv[1] = info; + + return (struct t_hashtable *)weechat_perl_exec (script_callback->script, + WEECHAT_SCRIPT_EXEC_HASHTABLE, + script_callback->function, + "sh", perl_argv); + } + + return NULL; +} + +/* + * weechat::hook_focus: hook a focus + */ + +XS (XS_weechat_api_hook_focus) +{ + char *result, *area, *function, *data; + dXSARGS; + + /* make C compiler happy */ + (void) cv; + + if (!perl_current_script || !perl_current_script->name) + { + WEECHAT_SCRIPT_MSG_NOT_INIT(PERL_CURRENT_SCRIPT_NAME, "hook_focus"); + PERL_RETURN_EMPTY; + } + + if (items < 3) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGS(PERL_CURRENT_SCRIPT_NAME, "hook_focus"); + PERL_RETURN_EMPTY; + } + + area = SvPV (ST (0), PL_na); + function = SvPV (ST (1), PL_na); + data = SvPV (ST (2), PL_na); + + result = script_ptr2str (script_api_hook_focus (weechat_perl_plugin, + perl_current_script, + area, + &weechat_perl_api_hook_focus_cb, + function, + data)); + + PERL_RETURN_STRING_FREE(result); +} + +/* * weechat::unhook: unhook something */ @@ -7213,6 +7279,7 @@ weechat_perl_api_init (pTHX) newXS ("weechat::hook_info", XS_weechat_api_hook_info, "weechat"); newXS ("weechat::hook_info_hashtable", XS_weechat_api_hook_info_hashtable, "weechat"); newXS ("weechat::hook_infolist", XS_weechat_api_hook_infolist, "weechat"); + newXS ("weechat::hook_focus", XS_weechat_api_hook_focus, "weechat"); newXS ("weechat::unhook", XS_weechat_api_unhook, "weechat"); newXS ("weechat::unhook_all", XS_weechat_api_unhook_all, "weechat"); newXS ("weechat::buffer_new", XS_weechat_api_buffer_new, "weechat"); diff --git a/src/plugins/scripts/python/weechat-python-api.c b/src/plugins/scripts/python/weechat-python-api.c index 05df01e70..162974f8c 100644 --- a/src/plugins/scripts/python/weechat-python-api.c +++ b/src/plugins/scripts/python/weechat-python-api.c @@ -3656,15 +3656,15 @@ weechat_python_api_hook_print (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_print (weechat_python_plugin, - python_current_script, - script_str2ptr (buffer), - tags, - message, - strip_colors, - &weechat_python_api_hook_print_cb, - function, - data)); + result = script_ptr2str (script_api_hook_print (weechat_python_plugin, + python_current_script, + script_str2ptr (buffer), + tags, + message, + strip_colors, + &weechat_python_api_hook_print_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -4012,12 +4012,12 @@ weechat_python_api_hook_config (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_config (weechat_python_plugin, - python_current_script, - option, - &weechat_python_api_hook_config_cb, - function, - data)); + result = script_ptr2str (script_api_hook_config (weechat_python_plugin, + python_current_script, + option, + &weechat_python_api_hook_config_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -4099,13 +4099,13 @@ weechat_python_api_hook_completion (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_completion (weechat_python_plugin, - python_current_script, - completion, - description, - &weechat_python_api_hook_completion_cb, - function, - data)); + result = script_ptr2str (script_api_hook_completion (weechat_python_plugin, + python_current_script, + completion, + description, + &weechat_python_api_hook_completion_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -4208,12 +4208,12 @@ weechat_python_api_hook_modifier (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_modifier (weechat_python_plugin, - python_current_script, - modifier, - &weechat_python_api_hook_modifier_cb, - function, - data)); + result = script_ptr2str (script_api_hook_modifier (weechat_python_plugin, + python_current_script, + modifier, + &weechat_python_api_hook_modifier_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -4313,14 +4313,14 @@ weechat_python_api_hook_info (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_info (weechat_python_plugin, - python_current_script, - info_name, - description, - args_description, - &weechat_python_api_hook_info_cb, - function, - data)); + result = script_ptr2str (script_api_hook_info (weechat_python_plugin, + python_current_script, + info_name, + description, + args_description, + &weechat_python_api_hook_info_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -4397,15 +4397,15 @@ weechat_python_api_hook_info_hashtable (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_info_hashtable (weechat_python_plugin, - python_current_script, - info_name, - description, - args_description, - output_description, - &weechat_python_api_hook_info_hashtable_cb, - function, - data)); + result = script_ptr2str (script_api_hook_info_hashtable (weechat_python_plugin, + python_current_script, + info_name, + description, + args_description, + output_description, + &weechat_python_api_hook_info_hashtable_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -4481,15 +4481,82 @@ weechat_python_api_hook_infolist (PyObject *self, PyObject *args) PYTHON_RETURN_EMPTY; } - result = script_ptr2str(script_api_hook_infolist (weechat_python_plugin, - python_current_script, - infolist_name, - description, - pointer_description, - args_description, - &weechat_python_api_hook_infolist_cb, - function, - data)); + result = script_ptr2str (script_api_hook_infolist (weechat_python_plugin, + python_current_script, + infolist_name, + description, + pointer_description, + args_description, + &weechat_python_api_hook_infolist_cb, + function, + data)); + + PYTHON_RETURN_STRING_FREE(result); +} + +/* + * weechat_python_api_hook_focus_cb: callback for focus hooked + */ + +struct t_hashtable * +weechat_python_api_hook_focus_cb (void *data, + struct t_hashtable *info) +{ + struct t_script_callback *script_callback; + void *python_argv[2]; + char empty_arg[1] = { '\0' }; + + script_callback = (struct t_script_callback *)data; + + if (script_callback && script_callback->function && script_callback->function[0]) + { + python_argv[0] = (script_callback->data) ? script_callback->data : empty_arg; + python_argv[1] = info; + + return (struct t_hashtable *)weechat_python_exec (script_callback->script, + WEECHAT_SCRIPT_EXEC_HASHTABLE, + script_callback->function, + "sh", python_argv); + } + + return NULL; +} + +/* + * weechat_python_api_hook_focus: hook a focus + */ + +static PyObject * +weechat_python_api_hook_focus (PyObject *self, PyObject *args) +{ + char *area, *function, *data, *result; + PyObject *object; + + /* make C compiler happy */ + (void) self; + + if (!python_current_script || !python_current_script->name) + { + WEECHAT_SCRIPT_MSG_NOT_INIT(PYTHON_CURRENT_SCRIPT_NAME, "hook_focus"); + PYTHON_RETURN_EMPTY; + } + + area = NULL; + function = NULL; + data = NULL; + + if (!PyArg_ParseTuple (args, "sss", &area, &function, &data)) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGS(PYTHON_CURRENT_SCRIPT_NAME, "hook_focus"); + PYTHON_RETURN_EMPTY; + } + + result = script_ptr2str (script_api_hook_focus (weechat_python_plugin, + python_current_script, + area, + &weechat_python_api_hook_focus_cb, + function, + data)); PYTHON_RETURN_STRING_FREE(result); } @@ -7555,6 +7622,7 @@ PyMethodDef weechat_python_funcs[] = { "hook_info", &weechat_python_api_hook_info, METH_VARARGS, "" }, { "hook_info_hashtable", &weechat_python_api_hook_info_hashtable, METH_VARARGS, "" }, { "hook_infolist", &weechat_python_api_hook_infolist, METH_VARARGS, "" }, + { "hook_focus", &weechat_python_api_hook_focus, METH_VARARGS, "" }, { "unhook", &weechat_python_api_unhook, METH_VARARGS, "" }, { "unhook_all", &weechat_python_api_unhook_all, METH_VARARGS, "" }, { "buffer_new", &weechat_python_api_buffer_new, METH_VARARGS, "" }, diff --git a/src/plugins/scripts/ruby/weechat-ruby-api.c b/src/plugins/scripts/ruby/weechat-ruby-api.c index 6e61c0e2e..69394dc73 100644 --- a/src/plugins/scripts/ruby/weechat-ruby-api.c +++ b/src/plugins/scripts/ruby/weechat-ruby-api.c @@ -4874,6 +4874,78 @@ weechat_ruby_api_hook_infolist (VALUE class, VALUE infolist_name, } /* + * weechat_ruby_api_hook_focus_cb: callback for focus hooked + */ + +struct t_hashtable * +weechat_ruby_api_hook_focus_cb (void *data, + struct t_hashtable *info) +{ + struct t_script_callback *script_callback; + void *ruby_argv[2]; + char empty_arg[1] = { '\0' }; + + script_callback = (struct t_script_callback *)data; + + if (script_callback && script_callback->function && script_callback->function[0]) + { + ruby_argv[0] = (script_callback->data) ? script_callback->data : empty_arg; + ruby_argv[1] = info; + + return (struct t_hashtable *)weechat_ruby_exec (script_callback->script, + WEECHAT_SCRIPT_EXEC_HASHTABLE, + script_callback->function, + "sh", ruby_argv); + } + + return NULL; +} + +/* + * weechat_ruby_api_hook_focus: hook a focus + */ + +static VALUE +weechat_ruby_api_hook_focus (VALUE class, VALUE area, VALUE function, + VALUE data) +{ + char *c_area, *c_function, *c_data, *result; + VALUE return_value; + + /* make C compiler happy */ + (void) class; + + if (!ruby_current_script || !ruby_current_script->name) + { + WEECHAT_SCRIPT_MSG_NOT_INIT(RUBY_CURRENT_SCRIPT_NAME, "hook_focus"); + RUBY_RETURN_EMPTY; + } + + if (NIL_P (area) || NIL_P (function) || NIL_P (data)) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGS(RUBY_CURRENT_SCRIPT_NAME, "hook_focus"); + RUBY_RETURN_EMPTY; + } + + Check_Type (area, T_STRING); + Check_Type (function, T_STRING); + Check_Type (data, T_STRING); + + c_area = StringValuePtr (area); + c_function = StringValuePtr (function); + c_data = StringValuePtr (data); + + result = script_ptr2str (script_api_hook_focus (weechat_ruby_plugin, + ruby_current_script, + c_area, + &weechat_ruby_api_hook_focus_cb, + c_function, + c_data)); + + RUBY_RETURN_STRING_FREE(result); +} + +/* * weechat_ruby_api_unhook: unhook something */ @@ -8279,6 +8351,7 @@ weechat_ruby_api_init (VALUE ruby_mWeechat) rb_define_module_function (ruby_mWeechat, "hook_info", &weechat_ruby_api_hook_info, 5); rb_define_module_function (ruby_mWeechat, "hook_info_hashtable", &weechat_ruby_api_hook_info_hashtable, 6); rb_define_module_function (ruby_mWeechat, "hook_infolist", &weechat_ruby_api_hook_infolist, 6); + rb_define_module_function (ruby_mWeechat, "hook_focus", &weechat_ruby_api_hook_focus, 3); rb_define_module_function (ruby_mWeechat, "unhook", &weechat_ruby_api_unhook, 1); rb_define_module_function (ruby_mWeechat, "unhook_all", &weechat_ruby_api_unhook_all, 0); rb_define_module_function (ruby_mWeechat, "buffer_new", &weechat_ruby_api_buffer_new, 5); diff --git a/src/plugins/scripts/script-api.c b/src/plugins/scripts/script-api.c index b7a6fbf55..9f05f6d2c 100644 --- a/src/plugins/scripts/script-api.c +++ b/src/plugins/scripts/script-api.c @@ -1329,6 +1329,43 @@ script_api_hook_infolist (struct t_weechat_plugin *weechat_plugin, } /* + * script_api_hook_focus: hook a focus + * return new hook, NULL if error + */ + +struct t_hook * +script_api_hook_focus (struct t_weechat_plugin *weechat_plugin, + struct t_plugin_script *script, + const char *area, + struct t_hashtable *(*callback)(void *data, + struct t_hashtable *info), + const char *function, + const char *data) +{ + struct t_script_callback *new_script_callback; + struct t_hook *new_hook; + + new_script_callback = script_callback_alloc (); + if (!new_script_callback) + return NULL; + + new_hook = weechat_hook_focus (area, callback, new_script_callback); + if (!new_hook) + { + script_callback_free_data (new_script_callback); + free (new_script_callback); + return NULL; + } + + script_callback_init (new_script_callback, script, function, data); + new_script_callback->hook = new_hook; + + script_callback_add (script, new_script_callback); + + return new_hook; +} + +/* * script_api_unhook: unhook something */ diff --git a/src/plugins/scripts/script-api.h b/src/plugins/scripts/script-api.h index 80ec4e2b9..c1c9dbe5b 100644 --- a/src/plugins/scripts/script-api.h +++ b/src/plugins/scripts/script-api.h @@ -276,6 +276,13 @@ extern struct t_hook *script_api_hook_infolist (struct t_weechat_plugin *weechat const char *arguments), const char *function, const char *data); +extern struct t_hook *script_api_hook_focus (struct t_weechat_plugin *weechat_plugin, + struct t_plugin_script *script, + const char *area, + struct t_hashtable *(*callback)(void *data, + struct t_hashtable *info), + const char *function, + const char *data); extern void script_api_unhook (struct t_weechat_plugin *weechat_plugin, struct t_plugin_script *script, struct t_hook *hook); diff --git a/src/plugins/scripts/tcl/weechat-tcl-api.c b/src/plugins/scripts/tcl/weechat-tcl-api.c index 5bc243bab..61570a5d2 100644 --- a/src/plugins/scripts/tcl/weechat-tcl-api.c +++ b/src/plugins/scripts/tcl/weechat-tcl-api.c @@ -4792,6 +4792,75 @@ weechat_tcl_api_hook_infolist (ClientData clientData, Tcl_Interp *interp, } /* + * weechat_tcl_api_hook_focus_cb: callback for focus hooked + */ + +struct t_hashtable * +weechat_tcl_api_hook_focus_cb (void *data, + struct t_hashtable *info) +{ + struct t_script_callback *script_callback; + void *tcl_argv[2]; + char empty_arg[1] = { '\0' }; + + script_callback = (struct t_script_callback *)data; + + if (script_callback && script_callback->function && script_callback->function[0]) + { + tcl_argv[0] = (script_callback->data) ? script_callback->data : empty_arg; + tcl_argv[1] = info; + + return (struct t_hashtable *)weechat_tcl_exec (script_callback->script, + WEECHAT_SCRIPT_EXEC_HASHTABLE, + script_callback->function, + "sh", tcl_argv); + } + + return NULL; +} + +/* + * weechat_tcl_api_hook_focus: hook a focus + */ + +static int +weechat_tcl_api_hook_focus (ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *objp; + char *result, *area, *function, *data; + int i; + + /* make C compiler happy */ + (void) clientData; + + if (!tcl_current_script || !tcl_current_script->name) + { + WEECHAT_SCRIPT_MSG_NOT_INIT(TCL_CURRENT_SCRIPT_NAME, "hook_focus"); + TCL_RETURN_EMPTY; + } + + if (objc < 4) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGS(TCL_CURRENT_SCRIPT_NAME, "hook_focus"); + TCL_RETURN_EMPTY; + } + + area = Tcl_GetStringFromObj (objv[1], &i); + function = Tcl_GetStringFromObj (objv[2], &i); + data = Tcl_GetStringFromObj (objv[3], &i); + + result = script_ptr2str (script_api_hook_focus (weechat_tcl_plugin, + tcl_current_script, + area, + &weechat_tcl_api_hook_focus_cb, + function, + data)); + + TCL_RETURN_STRING_FREE(result); +} + +/* * weechat_tcl_api_unhook: unhook something */ @@ -8205,6 +8274,8 @@ void weechat_tcl_api_init (Tcl_Interp *interp) weechat_tcl_api_hook_info_hashtable, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateObjCommand (interp, "weechat::hook_infolist", weechat_tcl_api_hook_infolist, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand (interp, "weechat::hook_focus", + weechat_tcl_api_hook_focus, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateObjCommand (interp, "weechat::unhook", weechat_tcl_api_unhook, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateObjCommand (interp, "weechat::unhook_all", diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h index 6a6ec60e0..99eead9ed 100644 --- a/src/plugins/weechat-plugin.h +++ b/src/plugins/weechat-plugin.h @@ -46,7 +46,7 @@ struct timeval; */ /* API version (used to check that plugin has same API and can be loaded) */ -#define WEECHAT_PLUGIN_API_VERSION "20110613-01" +#define WEECHAT_PLUGIN_API_VERSION "20110726-01" /* macros for defining plugin infos */ #define WEECHAT_PLUGIN_NAME(__name) \ @@ -584,6 +584,11 @@ struct t_weechat_plugin struct t_hdata *(*callback)(void *data, const char *hdata_name), void *callback_data); + struct t_hook *(*hook_focus) (struct t_weechat_plugin *plugin, + const char *area, + struct t_hashtable *(*callback)(void *data, + struct t_hashtable *info), + void *callback_data); void (*unhook) (struct t_hook *hook); void (*unhook_all) (struct t_weechat_plugin *plugin); @@ -1281,6 +1286,9 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); __data) \ weechat_plugin->hook_hdata(weechat_plugin, __hdata_name, \ __description, __callback, __data) +#define weechat_hook_focus(__area, __callback, __data) \ + weechat_plugin->hook_focus(weechat_plugin, __area, __callback, \ + __data) #define weechat_unhook(__hook) \ weechat_plugin->unhook( __hook) #define weechat_unhook_all() \ |