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