imported irssi.
[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
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "screen.h"
29 #include "gui-windows.h"
30
31 int mirc_colors[] = { 15, 0, 1, 2, 12, 6, 5, 4, 14, 10, 3, 11, 9, 13, 8, 7 };
32 static int scrollback_lines, scrollback_hours, scrollback_burst_remove;
33
34 static int scrollback_save_formats;
35 static GString *format;
36
37 static int last_color, last_flags;
38 static int next_xpos, next_ypos;
39
40 void gui_printtext(int xpos, int ypos, const char *str)
41 {
42         next_xpos = xpos;
43         next_ypos = ypos;
44
45         printtext_gui(str);
46
47         next_xpos = next_ypos = -1;
48 }
49
50 static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
51 {
52         LINE_REC *line;
53         time_t old_time;
54
55         old_time = time(NULL)-(scrollback_hours*3600)+1;
56         if (view->buffer->lines_count >=
57             scrollback_lines+scrollback_burst_remove) {
58                 /* remove lines by line count */
59                 while (view->buffer->lines_count > scrollback_lines) {
60                         line = view->buffer->lines->data;
61                         if (line->info.time >= old_time) {
62                                 /* too new line, don't remove yet */
63                                 break;
64                         }
65                         textbuffer_view_remove_line(view, line);
66                 }
67         }
68 }
69
70 static void get_colors(int flags, int *fg, int *bg)
71 {
72         if (flags & PRINTFLAG_MIRC_COLOR) {
73                 /* mirc colors - real range is 0..15, but after 16
74                    colors wrap to 0, 1, ... */
75                 *bg = *bg < 0 ? 0 : mirc_colors[*bg % 16];
76                 if (*fg > 0) *fg = mirc_colors[*fg % 16];
77         } else {
78                 /* default colors */
79                 *bg = *bg < 0 || *bg > 15 ? 0 : *bg;
80                 if (*fg > 8) *fg &= ~8;
81         }
82
83         if (*fg < 0 || *fg > 15) {
84                 *fg = *bg == 0 ? current_theme->default_color :
85                         current_theme->default_real_color;
86         }
87
88         if (flags & PRINTFLAG_REVERSE) {
89                 int tmp;
90
91                 tmp = *fg; *fg = *bg; *bg = tmp;
92         }
93
94         if (*fg == 8) *fg |= ATTR_COLOR8;
95         if (flags & PRINTFLAG_BOLD) {
96                 if (*fg == 0) *fg = current_theme->default_real_color;
97                 *fg |= 8;
98         }
99         if (flags & PRINTFLAG_UNDERLINE) *fg |= ATTR_UNDERLINE;
100         if (flags & PRINTFLAG_BLINK) *bg |= 0x08;
101 }
102
103 static void line_add_colors(TEXT_BUFFER_REC *buffer, LINE_REC **line,
104                             int fg, int bg, int flags)
105 {
106         unsigned char data[12];
107         int color, pos;
108
109         /* color should never have last bit on or it would be treated as a
110            command! */
111         color = (fg & 0x0f) | ((bg & 0x07) << 4);
112         pos = 0;
113
114         if (((fg & ATTR_COLOR8) == 0 && (fg|(bg << 4)) != last_color) ||
115             ((fg & ATTR_COLOR8) && (fg & 0xf0) != (last_color & 0xf0))) {
116                 data[pos++] = 0;
117                 data[pos++] = color == 0 ? LINE_CMD_COLOR0 : color;
118         }
119
120         if ((flags & PRINTFLAG_UNDERLINE) != (last_flags & PRINTFLAG_UNDERLINE)) {
121                 data[pos++] = 0;
122                 data[pos++] = LINE_CMD_UNDERLINE;
123         }
124         if (fg & ATTR_COLOR8) {
125                 data[pos++] = 0;
126                 data[pos++] = LINE_CMD_COLOR8;
127         }
128         if (bg & 0x08) {
129                 data[pos++] = 0;
130                 data[pos++] = LINE_CMD_BLINK;
131         }
132         if (flags & PRINTFLAG_INDENT) {
133                 data[pos++] = 0;
134                 data[pos++] = LINE_CMD_INDENT;
135         }
136
137         *line = textbuffer_insert(buffer, *line, data, pos, NULL);
138
139         last_flags = flags;
140         last_color = fg | (bg << 4);
141 }
142
143 static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line)
144 {
145         static const unsigned char eol[] = { 0, LINE_CMD_EOL };
146
147         *line = textbuffer_insert(view->buffer, *line, eol, 2, NULL);
148         textbuffer_view_insert_line(view, *line);
149 }
150
151 static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
152                                void *bgcolor, void *pflags,
153                                char *str, void *level)
154 {
155         TEXT_BUFFER_VIEW_REC *view;
156         LINE_REC *insert_after;
157         LINE_INFO_REC lineinfo;
158         int fg, bg, flags;
159
160         flags = GPOINTER_TO_INT(pflags);
161         fg = GPOINTER_TO_INT(fgcolor);
162         bg = GPOINTER_TO_INT(bgcolor);
163         get_colors(flags, &fg, &bg);
164
165         if (window == NULL) {
166                 g_return_if_fail(next_xpos != -1);
167
168                 wmove(stdscr, next_ypos, next_xpos);
169                 set_color(stdscr, fg | (bg << 4));
170                 addstr(str);
171                 next_xpos += strlen(str);
172                 return;
173         }
174
175         lineinfo.level = GPOINTER_TO_INT(level);
176         lineinfo.time = time(NULL);
177
178         view = WINDOW_GUI(window)->view;
179         insert_after = WINDOW_GUI(window)->use_insert_after ?
180                 WINDOW_GUI(window)->insert_after : view->buffer->cur_line;
181
182         if (flags & PRINTFLAG_NEWLINE)
183                 view_add_eol(view, &insert_after);
184         line_add_colors(view->buffer, &insert_after, fg, bg, flags);
185         textbuffer_insert(view->buffer, insert_after,
186                           str, strlen(str), &lineinfo);
187 }
188
189 static void sig_printtext_finished(WINDOW_REC *window)
190 {
191         TEXT_BUFFER_VIEW_REC *view;
192         LINE_REC *insert_after;
193
194         last_color = 0;
195         last_flags = 0;
196
197         view = WINDOW_GUI(window)->view;
198         insert_after = WINDOW_GUI(window)->use_insert_after ?
199                 WINDOW_GUI(window)->insert_after : view->buffer->cur_line;
200
201         view_add_eol(view, &insert_after);
202         remove_old_lines(view);
203 }
204
205 static void sig_print_format(THEME_REC *theme, const char *module,
206                              TEXT_DEST_REC *dest, void *formatnump,
207                              char **args)
208 {
209         FORMAT_REC *formats;
210         int formatnum, n;
211
212         if (!scrollback_save_formats)
213                 return;
214
215         formatnum = GPOINTER_TO_INT(formatnump);
216         formats = g_hash_table_lookup(default_formats, module);
217
218         /* <module><format_name><arg...> */
219         g_string_truncate(format, 0);
220
221         g_string_append_c(format, '\0');
222         g_string_append_c(format, (char)LINE_CMD_FORMAT);
223
224         g_string_append(format, module);
225
226         g_string_append_c(format, '\0');
227         g_string_append_c(format, (char)LINE_CMD_FORMAT);
228
229         g_string_append(format, formats[formatnum].tag);
230
231         for (n = 0; n < formats[formatnum].params; n++) {
232                 g_string_append_c(format, '\0');
233                 g_string_append_c(format, (char)LINE_CMD_FORMAT);
234
235                 g_string_append(format, args[n]);
236         }
237 }
238
239 static void read_settings(void)
240 {
241         scrollback_lines = settings_get_int("scrollback_lines");
242         scrollback_hours = settings_get_int("scrollback_hours");
243         scrollback_burst_remove = settings_get_int("scrollback_burst_remove");
244         scrollback_save_formats = settings_get_bool("scrollback_save_formats");
245 }
246
247 void gui_printtext_init(void)
248 {
249         next_xpos = next_ypos = -1;
250         format = g_string_new(NULL);
251
252         settings_add_int("history", "scrollback_lines", 500);
253         settings_add_int("history", "scrollback_hours", 24);
254         settings_add_int("history", "scrollback_burst_remove", 10);
255         settings_add_bool("history", "scrollback_save_formats", FALSE);
256
257         signal_add("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
258         signal_add("print text finished", (SIGNAL_FUNC) sig_printtext_finished);
259         signal_add("print format", (SIGNAL_FUNC) sig_print_format);
260         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
261         signal_add("beep", (SIGNAL_FUNC) beep);
262
263         read_settings();
264 }
265
266 void gui_printtext_deinit(void)
267 {
268         g_string_free(format, TRUE);
269
270         signal_remove("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
271         signal_remove("print text finished", (SIGNAL_FUNC) sig_printtext_finished);
272         signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
273         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
274         signal_remove("beep", (SIGNAL_FUNC) beep);
275 }