Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-text / term-curses.c
1 /*
2  term-curses.c : irssi
3
4     Copyright (C) 1999-2001 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 "term.h"
26 #include "mainwindows.h"
27
28 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
29 #  include <ncurses.h>
30 #else
31 #  include <curses.h>
32 #endif
33 #include <termios.h>
34 #include <signal.h>
35
36 #ifndef COLOR_PAIRS
37 #  define COLOR_PAIRS 64
38 #endif
39
40 #if defined (TIOCGWINSZ) && defined (HAVE_CURSES_RESIZETERM)
41 #  define USE_RESIZE_TERM
42 #endif
43
44 #ifndef _POSIX_VDISABLE
45 #  define _POSIX_VDISABLE 0
46 #endif
47
48 struct _TERM_WINDOW {
49         int x, y;
50         int width, height;
51         WINDOW *win;
52 };
53
54 TERM_WINDOW *root_window;
55
56 static int curs_x, curs_y;
57 static int freeze_refresh;
58 static struct termios old_tio;
59
60 static int init_curses(void)
61 {
62         char ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
63         int num;
64         struct termios tio;
65
66         if (!initscr())
67                 return FALSE;
68
69         cbreak(); noecho(); idlok(stdscr, 1);
70 #ifdef HAVE_CURSES_IDCOK
71         /*idcok(stdscr, 1); - disabled currently, causes redrawing problems with NetBSD */
72 #endif
73         intrflush(stdscr, FALSE); nodelay(stdscr, TRUE);
74
75         /* Disable INTR, QUIT, VDSUSP and SUSP keys */
76         if (tcgetattr(0, &old_tio) == 0) {
77                 memcpy(&tio, &old_tio, sizeof(tio));
78                 tio.c_cc[VINTR] = _POSIX_VDISABLE;
79                 tio.c_cc[VQUIT] = _POSIX_VDISABLE;
80 #ifdef VDSUSP
81                 tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
82 #endif
83 #ifdef VSUSP
84                 tio.c_cc[VSUSP] = _POSIX_VDISABLE;
85 #endif
86                 tcsetattr(0, TCSADRAIN, &tio);
87         }
88
89         if (has_colors())
90                 start_color();
91         else if (term_use_colors)
92                 term_use_colors = FALSE;
93
94 #ifdef HAVE_NCURSES_USE_DEFAULT_COLORS
95         /* this lets us to use the "default" background color for colors <= 7 so
96            background pixmaps etc. show up right */
97         use_default_colors();
98
99         for (num = 1; num < COLOR_PAIRS; num++)
100                 init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]);
101
102         init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more
103                                  people want dark grey than white on white.. */
104 #else
105         for (num = 1; num < COLOR_PAIRS; num++)
106                 init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]);
107         init_pair(63, 0, 0);
108 #endif
109
110         clear();
111         return TRUE;
112 }
113
114 static int term_init_int(void)
115 {
116         int ret;
117
118         ret = init_curses();
119         if (!ret) return 0;
120
121         curs_x = curs_y = 0;
122         freeze_refresh = 0;
123
124         root_window = g_new0(TERM_WINDOW, 1);
125         root_window->win = stdscr;
126
127         term_width = COLS;
128         term_height = LINES;
129         return ret;
130 }
131
132 static void term_deinit_int(void)
133 {
134         tcsetattr(0, TCSADRAIN, &old_tio);
135
136         endwin();
137         g_free_and_null(root_window);
138 }
139
140 int term_init(void)
141 {
142         if (!term_init_int())
143                 return FALSE;
144
145         settings_add_int("lookandfeel", "default_color", 7);
146         term_common_init();
147         return TRUE;
148 }
149
150 void term_deinit(void)
151 {
152         term_common_deinit();
153         term_deinit_int();
154 }
155
156 /* Resize terminal - if width or height is negative,
157    the new size is unknown and should be figured out somehow */
158 void term_resize(int width, int height)
159 {
160 #ifdef HAVE_CURSES_RESIZETERM
161         if (width < 0 || height < 0) {
162 #endif
163                 term_deinit_int();
164                 term_init_int();
165 #ifdef HAVE_CURSES_RESIZETERM
166         } else if (term_width != width || term_height != height) {
167                 term_width = width;
168                 term_height = height;
169                 resizeterm(term_height, term_width);
170         }
171 #endif
172 }
173
174 void term_resize_final(int width, int height)
175 {
176 #ifdef HAVE_CURSES_RESIZETERM
177         if (width < 0 || height < 0)
178                 mainwindows_recreate();
179 #else
180         mainwindows_recreate();
181 #endif
182 }
183
184 /* Returns TRUE if terminal has colors */
185 int term_has_colors(void)
186 {
187         return has_colors();
188 }
189
190 /* Force the colors on any way you can */
191 void term_force_colors(int set)
192 {
193         /* don't do anything with curses */
194 }
195
196 /* Clear screen */
197 void term_clear(void)
198 {
199         term_set_color(root_window, 0);
200         clear();
201 }
202
203 /* Beep */
204 void term_beep(void)
205 {
206         beep();
207 }
208
209 /* Create a new window in terminal */
210 TERM_WINDOW *term_window_create(int x, int y, int width, int height)
211 {
212         TERM_WINDOW *window;
213
214         window = g_new0(TERM_WINDOW, 1);
215         window->x = x; window->y = y;
216         window->width = width; window->height = height;
217         window->win = newwin(height, width, y, x);
218         if (window->win == NULL)
219                 g_error("newwin() failed: %d,%d %d,%d", x, y, width, height);
220         idlok(window->win, 1);
221
222         return window;
223 }
224
225 /* Destroy a terminal window */
226 void term_window_destroy(TERM_WINDOW *window)
227 {
228         delwin(window->win);
229         g_free(window);
230 }
231
232 /* Move/resize a window */
233 void term_window_move(TERM_WINDOW *window, int x, int y,
234                       int width, int height)
235 {
236         /* some checks to make sure the window is visible in screen,
237            otherwise curses could get nasty and not show our window anymore. */
238         if (width < 1) width = 1;
239         if (height < 1) height = 1;
240         if (x+width > term_width) x = term_width-width;
241         if (y+height > term_height) y = term_height-height;
242
243 #ifdef HAVE_CURSES_WRESIZE
244         if (window->width != width || window->height != height)
245                 wresize(window->win, height, width);
246         if (window->x != x || window->y != y)
247                 mvwin(window->win, y, x);
248 #else
249         if (window->width != width || window->height != height ||
250             window->x != x || window->y != y) {
251                 delwin(window->win);
252                 window->win = newwin(height, width, y, x);
253                 idlok(window->win, 1);
254         }
255 #endif
256         window->x = x; window->y = y;
257         window->width = width; window->height = height;
258 }
259
260 /* Clear window */
261 void term_window_clear(TERM_WINDOW *window)
262 {
263         werase(window->win);
264 }
265
266 /* Scroll window up/down */
267 void term_window_scroll(TERM_WINDOW *window, int count)
268 {
269         scrollok(window->win, TRUE);
270         wscrl(window->win, count);
271         scrollok(window->win, FALSE);
272 }
273
274 static int get_attr(int color)
275 {
276         int attr;
277
278         if (!term_use_colors)
279                 attr = (color & 0x70) ? A_REVERSE : 0;
280         else if ((color & 0xff) == 8 || (color & (0xff | ATTR_RESETFG)) == 0)
281                 attr = COLOR_PAIR(63);
282         else if ((color & 0x77) == 0)
283                 attr = A_NORMAL;
284         else {
285                 if (color & ATTR_RESETFG) {
286                         color &= ~0x0f;
287                         color |= settings_get_int("default_color");
288                 }
289                 attr = COLOR_PAIR((color&7) | ((color&0x70)>>1));
290         }
291
292         if ((color & 0x08) || (color & ATTR_BOLD)) attr |= A_BOLD;
293         if (color & ATTR_BLINK) attr |= A_BLINK;
294
295         if (color & ATTR_UNDERLINE) attr |= A_UNDERLINE;
296         if (color & ATTR_REVERSE) attr |= A_REVERSE;
297         return attr;
298 }
299
300 /* Change active color */
301 void term_set_color(TERM_WINDOW *window, int col)
302 {
303         wattrset(window->win, get_attr(col));
304         wbkgdset(window->win, ' ' | get_attr(col));
305 }
306
307 void term_move(TERM_WINDOW *window, int x, int y)
308 {
309         wmove(window->win, y, x);
310 }
311
312 void term_addch(TERM_WINDOW *window, char chr)
313 {
314         waddch(window->win, chr);
315 }
316
317 void term_add_unichar(TERM_WINDOW *window, unichar chr)
318 {
319 #ifdef WIDEC_CURSES
320         cchar_t wch;
321         wchar_t temp[2];
322         temp[0] = chr;
323         temp[1] = 0;
324         if (setcchar(&wch, temp, A_NORMAL, 0, NULL) == OK)
325                 wadd_wch(window->win, &wch);
326         else
327 #endif
328         waddch(window->win, chr);
329 }
330
331 void term_addstr(TERM_WINDOW *window, const char *str)
332 {
333         waddstr(window->win, (const char *) str);
334 }
335
336 void term_clrtoeol(TERM_WINDOW *window)
337 {
338         wclrtoeol(window->win);
339 }
340
341 void term_move_cursor(int x, int y)
342 {
343         curs_x = x;
344         curs_y = y;
345 }
346
347 void term_refresh_freeze(void)
348 {
349         freeze_refresh++;
350 }
351
352 void term_refresh_thaw(void)
353 {
354         if (freeze_refresh > 0) {
355                 freeze_refresh--;
356                 if (freeze_refresh == 0) term_refresh(NULL);
357         }
358 }
359
360 void term_refresh(TERM_WINDOW *window)
361 {
362         if (window != NULL)
363                 wnoutrefresh(window->win);
364
365         if (freeze_refresh == 0) {
366                 move(curs_y, curs_x);
367                 wnoutrefresh(stdscr);
368                 doupdate();
369         }
370 }
371
372 void term_stop(void)
373 {
374         term_deinit_int();
375         kill(getpid(), SIGTSTP);
376         term_init_int();
377         irssi_redraw();
378 }
379
380 void term_set_input_type(int type)
381 {
382 }
383
384 void term_gets(GArray *buffer, int *line_count)
385 {
386 #ifdef WIDEC_CURSES
387         wint_t key;
388 #else
389         int key;
390 #endif
391
392         for (;;) {
393 #ifdef WIDEC_CURSES
394                 if (get_wch(&key) == ERR)
395 #else
396                 if ((key = getch()) == ERR)
397 #endif
398                         break;
399 #ifdef KEY_RESIZE
400                 if (key == KEY_RESIZE)
401                         continue;
402 #endif
403
404                 g_array_append_val(buffer, key);
405                 if (key == '\r' || key == '\n')
406                         (*line_count)++;
407         }
408 }