Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-text / gui-printtext.c
1 /*
2  gui-printtext.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 "signals.h"
23 #include "settings.h"
24
25 #include "formats.h"
26 #include "printtext.h"
27
28 #include "term.h"
29 #include "gui-printtext.h"
30 #include "gui-windows.h"
31
32 int mirc_colors[] = { 15, 0, 1, 2, 12, 4, 5, 6, 14, 10, 3, 11, 9, 13, 8, 7 };
33 static int scrollback_lines, scrollback_time, scrollback_burst_remove;
34
35 static int next_xpos, next_ypos;
36
37 static GHashTable *indent_functions;
38 static INDENT_FUNC default_indent_func;
39
40 void gui_register_indent_func(const char *name, INDENT_FUNC func)
41 {
42         gpointer key, value;
43         GSList *list;
44
45         if (g_hash_table_lookup_extended(indent_functions, name, &key, &value)) {
46                 list = value;
47                 g_hash_table_remove(indent_functions, key);
48         } else {
49                 key = g_strdup(name);
50                 list = NULL;
51         }
52
53         list = g_slist_append(list, (void *) func);
54         g_hash_table_insert(indent_functions, key, list);
55 }
56
57 void gui_unregister_indent_func(const char *name, INDENT_FUNC func)
58 {
59         gpointer key, value;
60         GSList *list;
61
62         if (g_hash_table_lookup_extended(indent_functions, name, &key, &value)) {
63                 list = value;
64
65                 list = g_slist_remove(list, (void *) func);
66                 g_hash_table_remove(indent_functions, key);
67                 if (list == NULL)
68                         g_free(key);
69                 else
70                         g_hash_table_insert(indent_functions, key, list);
71         }
72
73         if (default_indent_func == func)
74                 gui_set_default_indent(NULL);
75
76         textbuffer_views_unregister_indent_func(func);
77 }
78
79 void gui_set_default_indent(const char *name)
80 {
81         GSList *list;
82
83         list = name == NULL ? NULL :
84                 g_hash_table_lookup(indent_functions, name);
85         default_indent_func = list == NULL ? NULL :
86                 (INDENT_FUNC) list->data;
87         gui_windows_reset_settings();
88 }
89
90 INDENT_FUNC get_default_indent_func(void)
91 {
92         return default_indent_func;
93 }
94
95 void gui_printtext(int xpos, int ypos, const char *str)
96 {
97         next_xpos = xpos;
98         next_ypos = ypos;
99
100         printtext_gui(str);
101
102         next_xpos = next_ypos = -1;
103 }
104
105 void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str)
106 {
107         GUI_WINDOW_REC *gui;
108
109         gui = WINDOW_GUI(dest->window);
110
111         gui->use_insert_after = TRUE;
112         gui->insert_after = prev;
113         format_send_to_gui(dest, str);
114         gui->use_insert_after = FALSE;
115 }
116
117 static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
118 {
119         LINE_REC *line;
120         time_t old_time;
121
122         old_time = time(NULL)-scrollback_time+1;
123         if (view->buffer->lines_count >=
124             scrollback_lines+scrollback_burst_remove) {
125                 /* remove lines by line count */
126                 while (view->buffer->lines_count > scrollback_lines) {
127                         line = view->buffer->first_line;
128                         if (line->info.time >= old_time ||
129                             scrollback_lines == 0) {
130                                 /* too new line, don't remove yet - also
131                                    if scrollback_lines is 0, we want to check
132                                    only scrollback_time setting. */
133                                 break;
134                         }
135                         textbuffer_view_remove_line(view, line);
136                 }
137         }
138 }
139
140 static void get_colors(int flags, int *fg, int *bg, int *attr)
141 {
142         if (flags & GUI_PRINT_FLAG_MIRC_COLOR) {
143                 /* mirc colors - real range is 0..15, but after 16
144                    colors wrap to 0, 1, ... */
145                 if (*bg >= 0) *bg = mirc_colors[*bg % 16];
146                 if (*fg >= 0) *fg = mirc_colors[*fg % 16];
147                 if (settings_get_bool("mirc_blink_fix"))
148                         *bg &= ~0x08;
149         }
150
151         if (*fg < 0 || *fg > 15)
152                 *fg = -1;
153         if (*bg < 0 || *bg > 15)
154                 *bg = -1;
155
156         *attr = 0;
157         if (flags & GUI_PRINT_FLAG_REVERSE) *attr |= ATTR_REVERSE;
158         if (flags & GUI_PRINT_FLAG_BOLD) *attr |= ATTR_BOLD;
159         if (flags & GUI_PRINT_FLAG_UNDERLINE) *attr |= ATTR_UNDERLINE;
160         if (flags & GUI_PRINT_FLAG_BLINK) *attr |= ATTR_BLINK;
161 }
162
163 static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line)
164 {
165         static const unsigned char eol[] = { 0, LINE_CMD_EOL };
166
167         *line = textbuffer_insert(view->buffer, *line, eol, 2, NULL);
168         textbuffer_view_insert_line(view, *line);
169 }
170
171 static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
172                                void *bgcolor, void *pflags,
173                                char *str, TEXT_DEST_REC *dest)
174 {
175         GUI_WINDOW_REC *gui;
176         TEXT_BUFFER_VIEW_REC *view;
177         LINE_REC *insert_after;
178         LINE_INFO_REC lineinfo;
179         int fg, bg, flags, attr;
180
181         flags = GPOINTER_TO_INT(pflags);
182         fg = GPOINTER_TO_INT(fgcolor);
183         bg = GPOINTER_TO_INT(bgcolor);
184         get_colors(flags, &fg, &bg, &attr);
185
186         if (window == NULL) {
187                 g_return_if_fail(next_xpos != -1);
188
189                 attr |= fg >= 0 ? fg : ATTR_RESETFG;
190                 attr |= bg >= 0 ? (bg << 4) : ATTR_RESETBG;
191                 term_set_color(root_window, attr);
192
193                 term_move(root_window, next_xpos, next_ypos);
194                 if (flags & GUI_PRINT_FLAG_CLRTOEOL)
195                         term_clrtoeol(root_window);
196                 term_addstr(root_window, str);
197                 next_xpos += strlen(str); /* FIXME utf8 or big5 */
198                 return;
199         }
200
201         lineinfo.level = dest == NULL ? 0 : dest->level;
202         lineinfo.time = time(NULL);
203
204         gui = WINDOW_GUI(window);
205         view = gui->view;
206         insert_after = gui->use_insert_after ?
207                 gui->insert_after : view->buffer->cur_line;
208
209         if (flags & GUI_PRINT_FLAG_NEWLINE) {
210                 view_add_eol(view, &insert_after);
211         }
212         textbuffer_line_add_colors(view->buffer, &insert_after, fg, bg, flags);
213
214         insert_after = textbuffer_insert(view->buffer, insert_after,
215                                          (unsigned char *) str,
216                                          strlen(str), &lineinfo);
217         if (gui->use_insert_after)
218                 gui->insert_after = insert_after;
219 }
220
221 static void sig_gui_printtext_finished(WINDOW_REC *window)
222 {
223         TEXT_BUFFER_VIEW_REC *view;
224         LINE_REC *insert_after;
225
226         view = WINDOW_GUI(window)->view;
227         insert_after = WINDOW_GUI(window)->use_insert_after ?
228                 WINDOW_GUI(window)->insert_after : view->buffer->cur_line;
229
230         view_add_eol(view, &insert_after);
231         remove_old_lines(view);
232 }
233
234 static void read_settings(void)
235 {
236         scrollback_lines = settings_get_int("scrollback_lines");
237         scrollback_time = settings_get_time("scrollback_time")/1000;
238         scrollback_burst_remove = settings_get_int("scrollback_burst_remove");
239 }
240
241 void gui_printtext_init(void)
242 {
243         next_xpos = next_ypos = -1;
244         default_indent_func = NULL;
245         indent_functions = g_hash_table_new((GHashFunc) g_str_hash,
246                                             (GCompareFunc) g_str_equal);
247
248         settings_add_int("history", "scrollback_lines", 500);
249         settings_add_time("history", "scrollback_time", "1day");
250         settings_add_int("history", "scrollback_burst_remove", 10);
251
252         signal_add("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
253         signal_add("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
254         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
255
256         read_settings();
257 }
258
259 void gui_printtext_deinit(void)
260 {
261         g_hash_table_destroy(indent_functions);
262
263         signal_remove("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
264         signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
265         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
266 }