Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-text / gui-readline.c
1 /*
2  gui-readline.c : irssi
3
4     Copyright (C) 1999 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "signals.h"
24 #include "misc.h"
25 #include "settings.h"
26 #include "special-vars.h"
27 #include "levels.h"
28 #include "servers.h"
29
30 #include "completion.h"
31 #include "command-history.h"
32 #include "keyboard.h"
33 #include "printtext.h"
34
35 #include "term.h"
36 #include "gui-entry.h"
37 #include "gui-windows.h"
38 #include "utf8.h"
39
40 #include <signal.h>
41
42 typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item);
43 typedef void (*ENTRY_REDIRECT_ENTRY_FUNC) (const char *line, void *data, SERVER_REC *server, WI_ITEM_REC *item);
44
45 typedef struct {
46         SIGNAL_FUNC func;
47         int flags;
48         void *data;
49 } ENTRY_REDIRECT_REC;
50
51 static KEYBOARD_REC *keyboard;
52 static ENTRY_REDIRECT_REC *redir;
53 static int escape_next_key;
54
55 static int readtag;
56 static unichar prev_key;
57 static GTimeVal last_keypress;
58
59 static int paste_detect_time, paste_verify_line_count;
60 static char *paste_entry;
61 static int paste_entry_pos;
62 static GArray *paste_buffer;
63
64 static char *paste_old_prompt;
65 static int paste_prompt, paste_line_count;
66 static int paste_join_multiline;
67 static int paste_timeout_id;
68
69 static void sig_input(void);
70
71 void input_listen_init(int handle)
72 {
73         readtag = g_input_add_poll(handle,
74                                    G_PRIORITY_HIGH, G_INPUT_READ,
75                                    (GInputFunction) sig_input, NULL);
76 }
77
78 void input_listen_deinit(void)
79 {
80         g_source_remove(readtag);
81         readtag = -1;
82 }
83
84 static void handle_key_redirect(int key)
85 {
86         ENTRY_REDIRECT_KEY_FUNC func;
87         void *data;
88
89         func = (ENTRY_REDIRECT_KEY_FUNC) redir->func;
90         data = redir->data;
91         g_free_and_null(redir);
92
93         gui_entry_set_prompt(active_entry, "");
94
95         if (func != NULL)
96                 func(key, data, active_win->active_server, active_win->active);
97 }
98
99 static void handle_entry_redirect(const char *line)
100 {
101         ENTRY_REDIRECT_ENTRY_FUNC func;
102         void *data;
103
104         gui_entry_set_hidden(active_entry, FALSE);
105
106         func = (ENTRY_REDIRECT_ENTRY_FUNC) redir->func;
107         data = redir->data;
108         g_free_and_null(redir);
109
110         gui_entry_set_prompt(active_entry, "");
111
112         if (func != NULL) {
113                 func(line, data, active_win->active_server,
114                      active_win->active);
115         }
116 }
117
118 static int get_scroll_count(void)
119 {
120         const char *str;
121         double count;
122
123         str = settings_get_str("scroll_page_count");
124         count = atof(str + (*str == '/'));
125         if (count == 0)
126                 count = 1;
127         else if (count < 0)
128                 count = active_mainwin->height-active_mainwin->statusbar_lines+count;
129         else if (count < 1)
130                 count = 1.0/count;
131
132         if (*str == '/') {
133                 count = (active_mainwin->height-active_mainwin->statusbar_lines)/count;
134         }
135         return (int)count;
136 }
137
138 static void window_prev_page(void)
139 {
140         gui_window_scroll(active_win, -get_scroll_count());
141 }
142
143 static void window_next_page(void)
144 {
145         gui_window_scroll(active_win, get_scroll_count());
146 }
147
148 static void paste_buffer_join_lines(GArray *buf)
149 {
150 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
151         unsigned int i, count, indent, line_len;
152         unichar *arr, *dest, *last_lf_pos;
153         int last_lf;
154
155         /* first check if we actually want to join anything. This is assuming
156            that we only want to join lines if
157
158            a) first line doesn't begin with whitespace
159            b) subsequent lines begin with same amount of whitespace
160            c) whenever there's no whitespace, goto a)
161
162            For example:
163
164            line 1
165              line 2
166              line 3
167            line 4
168            line 5
169              line 6
170
171            ->
172
173            line1 line2 line 3
174            line4
175            line5 line 6
176         */
177         if (buf->len == 0)
178                 return;
179
180         arr = (unichar *) paste_buffer->data;
181
182         /* first line */
183         if (IS_WHITE(arr[0]))
184                 return;
185
186         /* find the first beginning of indented line */
187         for (i = 1; i < buf->len; i++) {
188                 if (arr[i-1] == '\n' && IS_WHITE(arr[i]))
189                         break;
190         }
191         if (i == buf->len)
192                 return;
193
194         /* get how much indentation we have.. */
195         for (indent = 0; i < buf->len; i++, indent++) {
196                 if (!IS_WHITE(arr[i]))
197                         break;
198         }
199         if (i == buf->len)
200                 return;
201
202         /* now, enforce these to all subsequent lines */
203         count = indent; last_lf = TRUE;
204         for (; i < buf->len; i++) {
205                 if (last_lf) {
206                         if (IS_WHITE(arr[i]))
207                                 count++;
208                         else {
209                                 last_lf = FALSE;
210                                 if (count != 0 && count != indent)
211                                         return;
212                                 count = 0;
213                         }
214                 }
215                 if (arr[i] == '\n')
216                         last_lf = TRUE;
217         }
218
219         /* all looks fine - now remove the whitespace, but don't let lines
220            get longer than 400 chars */
221         dest = arr; last_lf = TRUE; last_lf_pos = NULL; line_len = 0;
222         for (i = 0; i < buf->len; i++) {
223                 if (last_lf && IS_WHITE(arr[i])) {
224                         /* whitespace, ignore */
225                 } else if (arr[i] == '\n') {
226                         if (!last_lf && i+1 != buf->len &&
227                             IS_WHITE(arr[i+1])) {
228                                 last_lf_pos = dest;
229                                 *dest++ = ' ';
230                         } else {
231                                 *dest++ = '\n'; /* double-LF */
232                                 line_len = 0;
233                                 last_lf_pos = NULL;
234                         }
235                         last_lf = TRUE;
236                 } else {
237                         last_lf = FALSE;
238                         if (++line_len >= 400 && last_lf_pos != NULL) {
239                                 memmove(last_lf_pos+1, last_lf_pos,
240                                         dest - last_lf_pos);
241                                 *last_lf_pos = '\n'; last_lf_pos = NULL;
242                                 line_len = 0;
243                                 dest++;
244                         }
245                         *dest++ = arr[i];
246                 }
247         }
248         g_array_set_size(buf, dest - arr);
249 }
250
251 static void paste_send(void)
252 {
253         HISTORY_REC *history;
254         unichar *arr;
255         GString *str;
256         char out[10], *text;
257         unsigned int i;
258
259         if (paste_join_multiline)
260                 paste_buffer_join_lines(paste_buffer);
261
262         arr = (unichar *) paste_buffer->data;
263         if (active_entry->text_len == 0)
264                 i = 0;
265         else {
266                 /* first line has to be kludged kind of to get pasting in the
267                    middle of line right.. */
268                 for (i = 0; i < paste_buffer->len; i++) {
269                         if (arr[i] == '\r' || arr[i] == '\n') {
270                                 i++;
271                                 break;
272                         }
273
274                         gui_entry_insert_char(active_entry, arr[i]);
275                 }
276
277                 text = gui_entry_get_text(active_entry);
278                 history = command_history_current(active_win);
279                 command_history_add(history, text);
280
281                 signal_emit("send command", 3, text,
282                             active_win->active_server, active_win->active);
283                 g_free(text);
284         }
285
286         /* rest of the lines */
287         str = g_string_new(NULL);
288         for (; i < paste_buffer->len; i++) {
289                 if (arr[i] == '\r' || arr[i] == '\n') {
290                         history = command_history_current(active_win);
291                         command_history_add(history, str->str);
292
293                         signal_emit("send command", 3, str->str,
294                                     active_win->active_server,
295                                     active_win->active);
296                         g_string_truncate(str, 0);
297                 } else if (active_entry->utf8) {
298                         out[g_unichar_to_utf8(arr[i], out)] = '\0';
299                         g_string_append(str, out);
300                 } else if (term_type == TERM_TYPE_BIG5) {
301                         if (arr[i] > 0xff)
302                                 g_string_append_c(str, (arr[i] >> 8) & 0xff);
303                         g_string_append_c(str, arr[i] & 0xff);
304                 } else {
305                         g_string_append_c(str, arr[i]);
306                 }
307         }
308
309         gui_entry_set_text(active_entry, str->str);
310         g_string_free(str, TRUE);
311 }
312
313 static void paste_flush(int send)
314 {
315         if (paste_prompt) {
316                 gui_entry_set_text(active_entry, paste_entry);
317                 gui_entry_set_pos(active_entry, paste_entry_pos);
318                 g_free_and_null(paste_entry);
319         }
320
321         if (send)
322                 paste_send();
323         g_array_set_size(paste_buffer, 0);
324
325         gui_entry_set_prompt(active_entry,
326                              paste_old_prompt == NULL ? "" : paste_old_prompt);
327         g_free(paste_old_prompt); paste_old_prompt = NULL;
328         paste_prompt = FALSE;
329
330         paste_line_count = 0;
331
332         gui_entry_redraw(active_entry);
333 }
334
335 static void insert_paste_prompt(void)
336 {
337         char *str;
338
339         paste_prompt = TRUE;
340         paste_old_prompt = g_strdup(active_entry->prompt);
341         printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
342                            TXT_PASTE_WARNING,
343                            paste_line_count,
344                            active_win->active == NULL ? "window" :
345                            active_win->active->visible_name);
346
347         str = format_get_text(MODULE_NAME, active_win, NULL, NULL,
348                               TXT_PASTE_PROMPT, 0, 0);
349         gui_entry_set_prompt(active_entry, str);
350         paste_entry = gui_entry_get_text(active_entry);
351         paste_entry_pos = gui_entry_get_pos(active_entry);
352         gui_entry_set_text(active_entry, "");
353         g_free(str);
354 }
355
356 static void sig_gui_key_pressed(gpointer keyp)
357 {
358         GTimeVal now;
359         unichar key;
360         char str[20];
361         int ret;
362
363         key = GPOINTER_TO_INT(keyp);
364
365         if (redir != NULL && redir->flags & ENTRY_REDIRECT_FLAG_HOTKEY) {
366                 handle_key_redirect(key);
367                 return;
368         }
369
370         g_get_current_time(&now);
371
372         if (key < 32) {
373                 /* control key */
374                 str[0] = '^';
375                 str[1] = (char)key+'@';
376                 str[2] = '\0';
377         } else if (key == 127) {
378                 str[0] = '^';
379                 str[1] = '?';
380                 str[2] = '\0';
381         } else if (!active_entry->utf8) {
382                 if (key <= 0xff) {
383                         str[0] = (char)key;
384                         str[1] = '\0';
385                 } else {
386                         str[0] = (char) (key >> 8);
387                         str[1] = (char) (key & 0xff);
388                         str[2] = '\0';
389                 }
390         } else {
391                 /* need to convert to utf8 */
392                 str[g_unichar_to_utf8(key, str)] = '\0';
393         }
394
395         if (strcmp(str, "^") == 0) {
396                 /* change it as ^^ */
397                 str[1] = '^';
398                 str[2] = '\0';
399         }
400
401         if (escape_next_key) {
402                 escape_next_key = FALSE;
403                 gui_entry_insert_char(active_entry, key);
404                 ret = 1;
405         } else {
406                 ret = key_pressed(keyboard, str);
407                 if (ret < 0) {
408                         /* key wasn't used for anything, print it */
409                         gui_entry_insert_char(active_entry, key);
410                 }
411         }
412
413         /* ret = 0 : some key create multiple characters - we're in the middle
414            of one. try to detect the keycombo as a single keypress rather than
415            multiple small onces to avoid incorrect paste detection.
416
417            don't count repeated keys so paste detection won't go on when
418            you're holding some key down */
419         if (ret != 0 && key != prev_key) {
420                 last_keypress = now;
421         }
422         prev_key = key;
423 }
424
425 static void key_send_line(void)
426 {
427         HISTORY_REC *history;
428         char *str;
429         int add_history;
430
431         str = gui_entry_get_text(active_entry);
432
433         /* we can't use gui_entry_get_text() later, since the entry might
434            have been destroyed after we get back */
435         add_history = *str != '\0';
436         history = command_history_current(active_win);
437
438         if (redir == NULL) {
439                 signal_emit("send command", 3, str,
440                             active_win->active_server,
441                             active_win->active);
442         } else {
443                 if (redir->flags & ENTRY_REDIRECT_FLAG_HIDDEN)
444                         add_history = 0;
445                 handle_entry_redirect(str);
446         }
447
448         if (add_history) {
449                 history = command_history_find(history);
450                 if (history != NULL)
451                         command_history_add(history, str);
452         }
453
454         if (active_entry != NULL)
455                 gui_entry_set_text(active_entry, "");
456         command_history_clear_pos(active_win);
457
458         g_free(str);
459 }
460
461 static void key_combo(void)
462 {
463 }
464
465 static void key_backward_history(void)
466 {
467         const char *text;
468         char *line;
469
470         line = gui_entry_get_text(active_entry);
471         text = command_history_prev(active_win, line);
472         gui_entry_set_text(active_entry, text);
473         g_free(line);
474 }
475
476 static void key_forward_history(void)
477 {
478         const char *text;
479         char *line;
480
481         line = gui_entry_get_text(active_entry);
482         text = command_history_next(active_win, line);
483         gui_entry_set_text(active_entry, text);
484         g_free(line);
485 }
486
487 static void key_beginning_of_line(void)
488 {
489         gui_entry_set_pos(active_entry, 0);
490 }
491
492 static void key_end_of_line(void)
493 {
494         gui_entry_set_pos(active_entry, active_entry->text_len);
495 }
496
497 static void key_backward_character(void)
498 {
499         gui_entry_move_pos(active_entry, -1);
500 }
501
502 static void key_forward_character(void)
503 {
504         gui_entry_move_pos(active_entry, 1);
505 }
506
507 static void key_backward_word(void)
508 {
509         gui_entry_move_words(active_entry, -1, FALSE);
510 }
511
512 static void key_forward_word(void)
513 {
514         gui_entry_move_words(active_entry, 1, FALSE);
515 }
516
517 static void key_backward_to_space(void)
518 {
519         gui_entry_move_words(active_entry, -1, TRUE);
520 }
521
522 static void key_forward_to_space(void)
523 {
524         gui_entry_move_words(active_entry, 1, TRUE);
525 }
526
527 static void key_erase_line(void)
528 {
529         gui_entry_set_pos(active_entry, active_entry->text_len);
530         gui_entry_erase(active_entry, active_entry->text_len, TRUE);
531 }
532
533 static void key_erase_to_beg_of_line(void)
534 {
535         int pos;
536
537         pos = gui_entry_get_pos(active_entry);
538         gui_entry_erase(active_entry, pos, TRUE);
539 }
540
541 static void key_erase_to_end_of_line(void)
542 {
543         int pos;
544
545         pos = gui_entry_get_pos(active_entry);
546         gui_entry_set_pos(active_entry, active_entry->text_len);
547         gui_entry_erase(active_entry, active_entry->text_len - pos, TRUE);
548 }
549
550 static void key_yank_from_cutbuffer(void)
551 {
552         char *cutbuffer;
553
554         cutbuffer = gui_entry_get_cutbuffer(active_entry);
555         if (cutbuffer != NULL) {
556                 gui_entry_insert_text(active_entry, cutbuffer);
557                 g_free(cutbuffer);
558         }
559 }
560
561 static void key_transpose_characters(void)
562 {
563         gui_entry_transpose_chars(active_entry);
564 }
565
566 static void key_transpose_words(void)
567 {
568         gui_entry_transpose_words(active_entry);
569 }
570
571 static void key_capitalize_word(void)
572 {
573         gui_entry_capitalize_word(active_entry);
574 }
575
576 static void key_downcase_word(void)
577 {
578         gui_entry_downcase_word(active_entry);
579 }
580 static void key_upcase_word(void)
581 {
582         gui_entry_upcase_word(active_entry);
583 }
584
585 static void key_delete_character(void)
586 {
587         if (gui_entry_get_pos(active_entry) < active_entry->text_len) {
588                 gui_entry_erase_cell(active_entry);
589         }
590 }
591
592 static void key_backspace(void)
593 {
594         gui_entry_erase(active_entry, 1, FALSE);
595 }
596
597 static void key_delete_previous_word(void)
598 {
599         gui_entry_erase_word(active_entry, FALSE);
600 }
601
602 static void key_delete_next_word(void)
603 {
604         gui_entry_erase_next_word(active_entry, FALSE);
605 }
606
607 static void key_delete_to_previous_space(void)
608 {
609         gui_entry_erase_word(active_entry, TRUE);
610 }
611
612 static void key_delete_to_next_space(void)
613 {
614         gui_entry_erase_next_word(active_entry, TRUE);
615 }
616
617 static gboolean paste_timeout(gpointer data)
618 {
619         if (paste_line_count == 0) {
620                 int i;
621
622                 for (i = 0; i < paste_buffer->len; i++) {
623                         unichar key = g_array_index(paste_buffer, unichar, i);
624                         signal_emit("gui key pressed", 1, GINT_TO_POINTER(key));
625                 }
626                 g_array_set_size(paste_buffer, 0);
627         } else if (paste_verify_line_count > 0 &&
628                    paste_line_count >= paste_verify_line_count &&
629                    active_win->active != NULL)
630                 insert_paste_prompt();
631         else
632                 paste_flush(TRUE);
633         paste_timeout_id = -1;
634         return FALSE;
635 }
636
637 static void sig_input(void)
638 {
639         if (!active_entry) {
640                 /* no active entry yet - wait until we have it */
641                 return;
642         }
643
644         if (paste_prompt) {
645                 GArray *buffer = g_array_new(FALSE, FALSE, sizeof(unichar));
646                 int line_count = 0;
647                 unichar key;
648                 term_gets(buffer, &line_count);
649                 key = g_array_index(buffer, unichar, 0);
650                 if (key == 11 || key == 3)
651                         paste_flush(key == 11);
652                 g_array_free(buffer, TRUE);
653         } else {
654                 term_gets(paste_buffer, &paste_line_count);
655                 if (paste_detect_time > 0 && paste_buffer->len >= 3) {
656                         if (paste_timeout_id != -1)
657                                 g_source_remove(paste_timeout_id);
658                         paste_timeout_id = g_timeout_add(paste_detect_time, paste_timeout, NULL);
659                 } else {
660                         int i;
661
662                         for (i = 0; i < paste_buffer->len; i++) {
663                                 unichar key = g_array_index(paste_buffer, unichar, i);
664                                 signal_emit("gui key pressed", 1, GINT_TO_POINTER(key));
665                         }
666                         g_array_set_size(paste_buffer, 0);
667                         paste_line_count = 0;
668                 }
669         }
670 }
671
672 time_t get_idle_time(void)
673 {
674         return last_keypress.tv_sec;
675 }
676
677 static void key_scroll_backward(void)
678 {
679         window_prev_page();
680 }
681
682 static void key_scroll_forward(void)
683 {
684         window_next_page();
685 }
686
687 static void key_scroll_start(void)
688 {
689         signal_emit("command scrollback home", 3, NULL, active_win->active_server, active_win->active);
690 }
691
692 static void key_scroll_end(void)
693 {
694         signal_emit("command scrollback end", 3, NULL, active_win->active_server, active_win->active);
695 }
696
697 static void key_change_window(const char *data)
698 {
699         signal_emit("command window goto", 3, data, active_win->active_server, active_win->active);
700 }
701
702 static void key_completion(int erase, int backward)
703 {
704         char *text, *line;
705         int pos;
706
707         text = gui_entry_get_text_and_pos(active_entry, &pos);
708         line = word_complete(active_win, text, &pos, erase, backward);
709         g_free(text);
710
711         if (line != NULL) {
712                 gui_entry_set_text(active_entry, line);
713                 gui_entry_set_pos(active_entry, pos);
714                 g_free(line);
715         }
716 }
717
718 static void key_word_completion_backward(void)
719 {
720         key_completion(FALSE, TRUE);
721 }
722
723 static void key_word_completion(void)
724 {
725         key_completion(FALSE, FALSE);
726 }
727
728 static void key_erase_completion(void)
729 {
730         key_completion(TRUE, FALSE);
731 }
732
733 static void key_check_replaces(void)
734 {
735         char *text, *line;
736         int pos;
737
738         text = gui_entry_get_text_and_pos(active_entry, &pos);
739         line = auto_word_complete(text, &pos);
740         g_free(text);
741
742         if (line != NULL) {
743                 gui_entry_set_text(active_entry, line);
744                 gui_entry_set_pos(active_entry, pos);
745                 g_free(line);
746         }
747 }
748
749 static void key_previous_window(void)
750 {
751         signal_emit("command window previous", 3, "", active_win->active_server, active_win->active);
752 }
753
754 static void key_next_window(void)
755 {
756         signal_emit("command window next", 3, "", active_win->active_server, active_win->active);
757 }
758
759 static void key_left_window(void)
760 {
761         signal_emit("command window left", 3, "", active_win->active_server, active_win->active);
762 }
763
764 static void key_right_window(void)
765 {
766         signal_emit("command window right", 3, "", active_win->active_server, active_win->active);
767 }
768
769 static void key_upper_window(void)
770 {
771         signal_emit("command window up", 3, "", active_win->active_server, active_win->active);
772 }
773
774 static void key_lower_window(void)
775 {
776         signal_emit("command window down", 3, "", active_win->active_server, active_win->active);
777 }
778
779 static void key_active_window(void)
780 {
781         signal_emit("command window goto", 3, "active", active_win->active_server, active_win->active);
782 }
783
784 static SERVER_REC *get_prev_server(SERVER_REC *current)
785 {
786         int pos;
787
788         if (current == NULL) {
789                 return servers != NULL ? g_slist_last(servers)->data :
790                         lookup_servers != NULL ?
791                         g_slist_last(lookup_servers)->data : NULL;
792         }
793
794         /* connect2 -> connect1 -> server2 -> server1 -> connect2 -> .. */
795
796         pos = g_slist_index(servers, current);
797         if (pos != -1) {
798                 if (pos > 0)
799                         return g_slist_nth(servers, pos-1)->data;
800                 if (lookup_servers != NULL)
801                         return g_slist_last(lookup_servers)->data;
802                 return g_slist_last(servers)->data;
803         }
804
805         pos = g_slist_index(lookup_servers, current);
806         g_assert(pos >= 0);
807
808         if (pos > 0)
809                 return g_slist_nth(lookup_servers, pos-1)->data;
810         if (servers != NULL)
811                 return g_slist_last(servers)->data;
812         return g_slist_last(lookup_servers)->data;
813 }
814
815 static SERVER_REC *get_next_server(SERVER_REC *current)
816 {
817         GSList *pos;
818
819         if (current == NULL) {
820                 return servers != NULL ? servers->data :
821                         lookup_servers != NULL ? lookup_servers->data : NULL;
822         }
823
824         /* server1 -> server2 -> connect1 -> connect2 -> server1 -> .. */
825
826         pos = g_slist_find(servers, current);
827         if (pos != NULL) {
828                 if (pos->next != NULL)
829                         return pos->next->data;
830                 if (lookup_servers != NULL)
831                         return lookup_servers->data;
832                 return servers->data;
833         }
834
835         pos = g_slist_find(lookup_servers, current);
836         g_assert(pos != NULL);
837
838         if (pos->next != NULL)
839                 return pos->next->data;
840         if (servers != NULL)
841                 return servers->data;
842         return lookup_servers->data;
843 }
844
845 static void key_previous_window_item(void)
846 {
847         SERVER_REC *server;
848
849         if (active_win->items != NULL) {
850                 signal_emit("command window item prev", 3, "",
851                             active_win->active_server, active_win->active);
852         } else if (servers != NULL || lookup_servers != NULL) {
853                 /* change server */
854                 server = active_win->active_server;
855                 if (server == NULL)
856                         server = active_win->connect_server;
857                 server = get_prev_server(server);
858                 signal_emit("command window server", 3, server->tag,
859                             active_win->active_server, active_win->active);
860         }
861 }
862
863 static void key_next_window_item(void)
864 {
865         SERVER_REC *server;
866
867         if (active_win->items != NULL) {
868                 signal_emit("command window item next", 3, "",
869                             active_win->active_server, active_win->active);
870         } else if (servers != NULL || lookup_servers != NULL) {
871                 /* change server */
872                 server = active_win->active_server;
873                 if (server == NULL)
874                         server = active_win->connect_server;
875                 server = get_next_server(server);
876                 signal_emit("command window server", 3, server->tag,
877                             active_win->active_server, active_win->active);
878         }
879 }
880
881 static void key_escape(void)
882 {
883         escape_next_key = TRUE;
884 }
885
886 static void key_insert_text(const char *data)
887 {
888         char *str;
889
890         str = parse_special_string(data, active_win->active_server,
891                                    active_win->active, "", NULL, 0);
892         gui_entry_insert_text(active_entry, str);
893         g_free(str);
894 }
895
896 static void key_sig_stop(void)
897 {
898         term_stop();
899 }
900
901 static void sig_window_auto_changed(void)
902 {
903         char *text;
904
905         if (active_entry == NULL)
906                 return;
907
908         text = gui_entry_get_text(active_entry);
909         command_history_next(active_win, text);
910         gui_entry_set_text(active_entry, "");
911         g_free(text);
912 }
913
914 static void sig_gui_entry_redirect(SIGNAL_FUNC func, const char *entry,
915                                    void *flags, void *data)
916 {
917         redir = g_new0(ENTRY_REDIRECT_REC, 1);
918         redir->func = func;
919         redir->flags = GPOINTER_TO_INT(flags);
920         redir->data = data;
921
922         if (redir->flags & ENTRY_REDIRECT_FLAG_HIDDEN)
923                 gui_entry_set_hidden(active_entry, TRUE);
924         gui_entry_set_prompt(active_entry, entry);
925 }
926
927 static void setup_changed(void)
928 {
929         paste_detect_time = settings_get_time("paste_detect_time");
930
931         paste_verify_line_count = settings_get_int("paste_verify_line_count");
932         paste_join_multiline = settings_get_bool("paste_join_multiline");
933 }
934
935 void gui_readline_init(void)
936 {
937         static char changekeys[] = "1234567890qwertyuio";
938         char *key, data[MAX_INT_STRLEN];
939         int n;
940
941         escape_next_key = FALSE;
942         redir = NULL;
943         paste_entry = NULL;
944         paste_entry_pos = 0;
945         paste_buffer = g_array_new(FALSE, FALSE, sizeof(unichar));
946         paste_old_prompt = NULL;
947         paste_timeout_id = -1;
948         g_get_current_time(&last_keypress);
949         input_listen_init(STDIN_FILENO);
950
951         settings_add_str("history", "scroll_page_count", "/2");
952         settings_add_time("misc", "paste_detect_time", "5msecs");
953         /* NOTE: function keys can generate at least 5 characters long
954            keycodes. this must be larger to allow them to work. */
955         settings_add_int("misc", "paste_verify_line_count", 5);
956         settings_add_bool("misc", "paste_join_multiline", TRUE);
957         setup_changed();
958
959         keyboard = keyboard_create(NULL);
960         key_configure_freeze();
961
962         key_bind("key", NULL, " ", "space", (SIGNAL_FUNC) key_combo);
963         key_bind("key", NULL, "^M", "return", (SIGNAL_FUNC) key_combo);
964         key_bind("key", NULL, "^J", "return", (SIGNAL_FUNC) key_combo);
965         key_bind("key", NULL, "^H", "backspace", (SIGNAL_FUNC) key_combo);
966         key_bind("key", NULL, "^?", "backspace", (SIGNAL_FUNC) key_combo);
967         key_bind("key", NULL, "^I", "tab", (SIGNAL_FUNC) key_combo);
968
969         /* meta */
970         key_bind("key", NULL, "^[", "meta", (SIGNAL_FUNC) key_combo);
971         key_bind("key", NULL, "meta-[", "meta2", (SIGNAL_FUNC) key_combo);
972         key_bind("key", NULL, "meta-O", "meta2", (SIGNAL_FUNC) key_combo);
973         key_bind("key", NULL, "meta-[O", "meta2", (SIGNAL_FUNC) key_combo);
974
975         /* arrow keys */
976         key_bind("key", NULL, "meta2-A", "up", (SIGNAL_FUNC) key_combo);
977         key_bind("key", NULL, "meta2-B", "down", (SIGNAL_FUNC) key_combo);
978         key_bind("key", NULL, "meta2-C", "right", (SIGNAL_FUNC) key_combo);
979         key_bind("key", NULL, "meta2-D", "left", (SIGNAL_FUNC) key_combo);
980
981         key_bind("key", NULL, "meta2-1~", "home", (SIGNAL_FUNC) key_combo);
982         key_bind("key", NULL, "meta2-7~", "home", (SIGNAL_FUNC) key_combo);
983         key_bind("key", NULL, "meta2-H", "home", (SIGNAL_FUNC) key_combo);
984
985         key_bind("key", NULL, "meta2-4~", "end", (SIGNAL_FUNC) key_combo);
986         key_bind("key", NULL, "meta2-8~", "end", (SIGNAL_FUNC) key_combo);
987         key_bind("key", NULL, "meta2-F", "end", (SIGNAL_FUNC) key_combo);
988
989         key_bind("key", NULL, "meta2-5~", "prior", (SIGNAL_FUNC) key_combo);
990         key_bind("key", NULL, "meta2-I", "prior", (SIGNAL_FUNC) key_combo);
991         key_bind("key", NULL, "meta2-6~", "next", (SIGNAL_FUNC) key_combo);
992         key_bind("key", NULL, "meta2-G", "next", (SIGNAL_FUNC) key_combo);
993
994         key_bind("key", NULL, "meta2-2~", "insert", (SIGNAL_FUNC) key_combo);
995         key_bind("key", NULL, "meta2-3~", "delete", (SIGNAL_FUNC) key_combo);
996
997         key_bind("key", NULL, "meta2-d", "cleft", (SIGNAL_FUNC) key_combo);
998         key_bind("key", NULL, "meta2-c", "cright", (SIGNAL_FUNC) key_combo);
999         key_bind("key", NULL, "meta2-5D", "cleft", (SIGNAL_FUNC) key_combo);
1000         key_bind("key", NULL, "meta2-5C", "cright", (SIGNAL_FUNC) key_combo);
1001         key_bind("key", NULL, "meta2-1;5D", "cleft", (SIGNAL_FUNC) key_combo);
1002         key_bind("key", NULL, "meta2-1;5C", "cright", (SIGNAL_FUNC) key_combo);
1003
1004         key_bind("key", NULL, "meta2-1;3A", "mup", (SIGNAL_FUNC) key_combo);
1005         key_bind("key", NULL, "meta2-1;3B", "mdown", (SIGNAL_FUNC) key_combo);
1006         key_bind("key", NULL, "meta2-1;3D", "mleft", (SIGNAL_FUNC) key_combo);
1007         key_bind("key", NULL, "meta2-1;3C", "mright", (SIGNAL_FUNC) key_combo);
1008         key_bind("key", NULL, "meta-up", "mup", (SIGNAL_FUNC) key_combo);
1009         key_bind("key", NULL, "meta-down", "mdown", (SIGNAL_FUNC) key_combo);
1010         key_bind("key", NULL, "meta-left", "mleft", (SIGNAL_FUNC) key_combo);
1011         key_bind("key", NULL, "meta-right", "mright", (SIGNAL_FUNC) key_combo);
1012
1013         key_bind("key", NULL, "meta2-1;5~", "chome", (SIGNAL_FUNC) key_combo);
1014         key_bind("key", NULL, "meta2-7;5~", "chome", (SIGNAL_FUNC) key_combo);
1015         key_bind("key", NULL, "meta2-5H", "chome", (SIGNAL_FUNC) key_combo);
1016         key_bind("key", NULL, "meta2-1;5H", "chome", (SIGNAL_FUNC) key_combo);
1017
1018         key_bind("key", NULL, "meta2-4;5~", "cend", (SIGNAL_FUNC) key_combo);
1019         key_bind("key", NULL, "meta2-8;5~", "cend", (SIGNAL_FUNC) key_combo);
1020         key_bind("key", NULL, "meta2-5F", "cend", (SIGNAL_FUNC) key_combo);
1021         key_bind("key", NULL, "meta2-1;5F", "cend", (SIGNAL_FUNC) key_combo);
1022
1023         /* cursor movement */
1024         key_bind("backward_character", "Move the cursor a character backward", "left", NULL, (SIGNAL_FUNC) key_backward_character);
1025         key_bind("forward_character", "Move the cursor a character forward", "right", NULL, (SIGNAL_FUNC) key_forward_character);
1026         key_bind("backward_word", "Move the cursor a word backward", "cleft", NULL, (SIGNAL_FUNC) key_backward_word);
1027         key_bind("backward_word", NULL, "meta-b", NULL, (SIGNAL_FUNC) key_backward_word);
1028         key_bind("forward_word", "Move the cursor a word forward", "cright", NULL, (SIGNAL_FUNC) key_forward_word);
1029         key_bind("forward_word", NULL, "meta-f", NULL, (SIGNAL_FUNC) key_forward_word);
1030         key_bind("backward_to_space", "Move the cursor backward to a space", NULL, NULL, (SIGNAL_FUNC) key_backward_to_space);
1031         key_bind("forward_to_space", "Move the cursor forward to a space", NULL, NULL, (SIGNAL_FUNC) key_forward_to_space);
1032         key_bind("beginning_of_line", "Move the cursor to the beginning of the line", "home", NULL, (SIGNAL_FUNC) key_beginning_of_line);
1033         key_bind("beginning_of_line", NULL, "^A", NULL, (SIGNAL_FUNC) key_beginning_of_line);
1034         key_bind("end_of_line", "Move the cursor to the end of the line", "end", NULL, (SIGNAL_FUNC) key_end_of_line);
1035         key_bind("end_of_line", NULL, "^E", NULL, (SIGNAL_FUNC) key_end_of_line);
1036
1037         /* history */
1038         key_bind("backward_history", "Go back one line in the history", "up", NULL, (SIGNAL_FUNC) key_backward_history);
1039         key_bind("forward_history", "Go forward one line in the history", "down", NULL, (SIGNAL_FUNC) key_forward_history);
1040
1041         /* line editing */
1042         key_bind("backspace", "Delete the previous character", "backspace", NULL, (SIGNAL_FUNC) key_backspace);
1043         key_bind("delete_character", "Delete the current character", "delete", NULL, (SIGNAL_FUNC) key_delete_character);
1044         key_bind("delete_character", NULL, "^D", NULL, (SIGNAL_FUNC) key_delete_character);
1045         key_bind("delete_next_word", "Delete the word after the cursor", "meta-d", NULL, (SIGNAL_FUNC) key_delete_next_word);
1046         key_bind("delete_previous_word", "Delete the word before the cursor", "meta-backspace", NULL, (SIGNAL_FUNC) key_delete_previous_word);
1047         key_bind("delete_to_previous_space", "Delete up to the previous space", "^W", NULL, (SIGNAL_FUNC) key_delete_to_previous_space);
1048         key_bind("delete_to_next_space", "Delete up to the next space", "", NULL, (SIGNAL_FUNC) key_delete_to_next_space);
1049         key_bind("erase_line", "Erase the whole input line", "^U", NULL, (SIGNAL_FUNC) key_erase_line);
1050         key_bind("erase_to_beg_of_line", "Erase everything before the cursor", NULL, NULL, (SIGNAL_FUNC) key_erase_to_beg_of_line);
1051         key_bind("erase_to_end_of_line", "Erase everything after the cursor", "^K", NULL, (SIGNAL_FUNC) key_erase_to_end_of_line);
1052         key_bind("yank_from_cutbuffer", "\"Undelete\", paste the last deleted text", "^Y", NULL, (SIGNAL_FUNC) key_yank_from_cutbuffer);
1053         key_bind("transpose_characters", "Swap current and previous character", "^T", NULL, (SIGNAL_FUNC) key_transpose_characters);
1054         key_bind("transpose_words", "Swap current and previous word", NULL, NULL, (SIGNAL_FUNC) key_transpose_words);
1055         key_bind("capitalize_word", "Capitalize the current word", NULL, NULL, (SIGNAL_FUNC) key_capitalize_word);
1056         key_bind("downcase_word", "Downcase the current word", NULL, NULL, (SIGNAL_FUNC) key_downcase_word);
1057         key_bind("upcase_word", "Upcase the current word", NULL, NULL, (SIGNAL_FUNC) key_upcase_word);
1058
1059         /* line transmitting */
1060         key_bind("send_line", "Execute the input line", "return", NULL, (SIGNAL_FUNC) key_send_line);
1061         key_bind("word_completion_backward", "", NULL, NULL, (SIGNAL_FUNC) key_word_completion_backward);
1062         key_bind("word_completion", "Complete the current word", "tab", NULL, (SIGNAL_FUNC) key_word_completion);
1063         key_bind("erase_completion", "Remove the completion added by word_completion", "meta-k", NULL, (SIGNAL_FUNC) key_erase_completion);
1064         key_bind("check_replaces", "Check word replaces", NULL, NULL, (SIGNAL_FUNC) key_check_replaces);
1065
1066         /* window managing */
1067         key_bind("previous_window", "Go to the previous window", "^P", NULL, (SIGNAL_FUNC) key_previous_window);
1068         key_bind("next_window", "Go to the next window", "^N", NULL, (SIGNAL_FUNC) key_next_window);
1069         key_bind("upper_window", "Go to the split window above", "mup", NULL, (SIGNAL_FUNC) key_upper_window);
1070         key_bind("lower_window", "Go to the split window below", "mdown", NULL, (SIGNAL_FUNC) key_lower_window);
1071         key_bind("left_window", "Go to the previous window in the current split window", "mleft", NULL, (SIGNAL_FUNC) key_left_window);
1072         key_bind("right_window", "Go to the next window in the current split window", "mright", NULL, (SIGNAL_FUNC) key_right_window);
1073         key_bind("active_window", "Go to next window with the highest activity", "meta-a", NULL, (SIGNAL_FUNC) key_active_window);
1074         key_bind("next_window_item", "Go to the next channel/query. In empty windows change to the next server", "^X", NULL, (SIGNAL_FUNC) key_next_window_item);
1075         key_bind("previous_window_item", "Go to the previous channel/query. In empty windows change to the previous server", NULL, NULL, (SIGNAL_FUNC) key_previous_window_item);
1076
1077         key_bind("refresh_screen", "Redraw screen", "^L", NULL, (SIGNAL_FUNC) irssi_redraw);
1078         key_bind("scroll_backward", "Scroll to previous page", "prior", NULL, (SIGNAL_FUNC) key_scroll_backward);
1079         key_bind("scroll_backward", NULL, "meta-p", NULL, (SIGNAL_FUNC) key_scroll_backward);
1080         key_bind("scroll_forward", "Scroll to next page", "next", NULL, (SIGNAL_FUNC) key_scroll_forward);
1081         key_bind("scroll_forward", NULL, "meta-n", NULL, (SIGNAL_FUNC) key_scroll_forward);
1082         key_bind("scroll_start", "Scroll to the beginning of the window", "chome", NULL, (SIGNAL_FUNC) key_scroll_start);
1083         key_bind("scroll_end", "Scroll to the end of the window", "cend", NULL, (SIGNAL_FUNC) key_scroll_end);
1084
1085         /* inserting special input characters to line.. */
1086         key_bind("escape_char", "Insert the next character exactly as-is to input line", NULL, NULL, (SIGNAL_FUNC) key_escape);
1087         key_bind("insert_text", "Append text to line", NULL, NULL, (SIGNAL_FUNC) key_insert_text);
1088
1089         /* autoreplaces */
1090         key_bind("multi", NULL, "return", "check_replaces;send_line", NULL);
1091         key_bind("multi", NULL, "space", "check_replaces;insert_text  ", NULL);
1092
1093         /* moving between windows */
1094         for (n = 0; changekeys[n] != '\0'; n++) {
1095                 key = g_strdup_printf("meta-%c", changekeys[n]);
1096                 ltoa(data, n+1);
1097                 key_bind("change_window", "Change window", key, data, (SIGNAL_FUNC) key_change_window);
1098                 g_free(key);
1099         }
1100
1101         /* misc */
1102         key_bind("stop_irc", "Send SIGSTOP to client", "^Z", NULL, (SIGNAL_FUNC) key_sig_stop);
1103
1104         key_configure_thaw();
1105
1106         signal_add("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
1107         signal_add("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect);
1108         signal_add("gui key pressed", (SIGNAL_FUNC) sig_gui_key_pressed);
1109         signal_add("setup changed", (SIGNAL_FUNC) setup_changed);
1110 }
1111
1112 void gui_readline_deinit(void)
1113 {
1114         input_listen_deinit();
1115
1116         key_configure_freeze();
1117
1118         key_unbind("backward_character", (SIGNAL_FUNC) key_backward_character);
1119         key_unbind("forward_character", (SIGNAL_FUNC) key_forward_character);
1120         key_unbind("backward_word", (SIGNAL_FUNC) key_backward_word);
1121         key_unbind("forward_word", (SIGNAL_FUNC) key_forward_word);
1122         key_unbind("backward_to_space", (SIGNAL_FUNC) key_backward_to_space);
1123         key_unbind("forward_to_space", (SIGNAL_FUNC) key_forward_to_space);
1124         key_unbind("beginning_of_line", (SIGNAL_FUNC) key_beginning_of_line);
1125         key_unbind("end_of_line", (SIGNAL_FUNC) key_end_of_line);
1126
1127         key_unbind("backward_history", (SIGNAL_FUNC) key_backward_history);
1128         key_unbind("forward_history", (SIGNAL_FUNC) key_forward_history);
1129
1130         key_unbind("backspace", (SIGNAL_FUNC) key_backspace);
1131         key_unbind("delete_character", (SIGNAL_FUNC) key_delete_character);
1132         key_unbind("delete_next_word", (SIGNAL_FUNC) key_delete_next_word);
1133         key_unbind("delete_previous_word", (SIGNAL_FUNC) key_delete_previous_word);
1134         key_unbind("delete_to_next_space", (SIGNAL_FUNC) key_delete_to_next_space);
1135         key_unbind("delete_to_previous_space", (SIGNAL_FUNC) key_delete_to_previous_space);
1136         key_unbind("erase_line", (SIGNAL_FUNC) key_erase_line);
1137         key_unbind("erase_to_beg_of_line", (SIGNAL_FUNC) key_erase_to_beg_of_line);
1138         key_unbind("erase_to_end_of_line", (SIGNAL_FUNC) key_erase_to_end_of_line);
1139         key_unbind("yank_from_cutbuffer", (SIGNAL_FUNC) key_yank_from_cutbuffer);
1140         key_unbind("transpose_characters", (SIGNAL_FUNC) key_transpose_characters);
1141         key_unbind("transpose_words", (SIGNAL_FUNC) key_transpose_words);
1142
1143         key_unbind("capitalize_word", (SIGNAL_FUNC) key_capitalize_word);
1144         key_unbind("downcase_word", (SIGNAL_FUNC) key_downcase_word);
1145         key_unbind("upcase_word", (SIGNAL_FUNC) key_upcase_word);
1146
1147         key_unbind("send_line", (SIGNAL_FUNC) key_send_line);
1148         key_unbind("word_completion_backward", (SIGNAL_FUNC) key_word_completion_backward);
1149         key_unbind("word_completion", (SIGNAL_FUNC) key_word_completion);
1150         key_unbind("erase_completion", (SIGNAL_FUNC) key_erase_completion);
1151         key_unbind("check_replaces", (SIGNAL_FUNC) key_check_replaces);
1152
1153         key_unbind("previous_window", (SIGNAL_FUNC) key_previous_window);
1154         key_unbind("next_window", (SIGNAL_FUNC) key_next_window);
1155         key_unbind("upper_window", (SIGNAL_FUNC) key_upper_window);
1156         key_unbind("lower_window", (SIGNAL_FUNC) key_lower_window);
1157         key_unbind("left_window", (SIGNAL_FUNC) key_left_window);
1158         key_unbind("right_window", (SIGNAL_FUNC) key_right_window);
1159         key_unbind("active_window", (SIGNAL_FUNC) key_active_window);
1160         key_unbind("next_window_item", (SIGNAL_FUNC) key_next_window_item);
1161         key_unbind("previous_window_item", (SIGNAL_FUNC) key_previous_window_item);
1162
1163         key_unbind("refresh_screen", (SIGNAL_FUNC) irssi_redraw);
1164         key_unbind("scroll_backward", (SIGNAL_FUNC) key_scroll_backward);
1165         key_unbind("scroll_forward", (SIGNAL_FUNC) key_scroll_forward);
1166         key_unbind("scroll_start", (SIGNAL_FUNC) key_scroll_start);
1167         key_unbind("scroll_end", (SIGNAL_FUNC) key_scroll_end);
1168
1169         key_unbind("escape_char", (SIGNAL_FUNC) key_escape);
1170         key_unbind("insert_text", (SIGNAL_FUNC) key_insert_text);
1171         key_unbind("change_window", (SIGNAL_FUNC) key_change_window);
1172         key_unbind("stop_irc", (SIGNAL_FUNC) key_sig_stop);
1173         keyboard_destroy(keyboard);
1174         g_array_free(paste_buffer, TRUE);
1175
1176         key_configure_thaw();
1177
1178         signal_remove("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
1179         signal_remove("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect);
1180         signal_remove("gui key pressed", (SIGNAL_FUNC) sig_gui_key_pressed);
1181         signal_remove("setup changed", (SIGNAL_FUNC) setup_changed);
1182 }