Merged 0.7.99 irssi.
[runtime.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 int term_width, term_height;
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 & 0x0f) == 8) && (color & ATTR_BOLD) == 0)
281                 attr = (A_DIM | 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)/2));
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, int chr)
313 {
314         waddch(window->win, chr);
315 }
316
317 void term_addstr(TERM_WINDOW *window, const char *str)
318 {
319         waddstr(window->win, (const char *) str);
320 }
321
322 void term_clrtoeol(TERM_WINDOW *window)
323 {
324         wclrtoeol(window->win);
325 }
326
327 void term_move_cursor(int x, int y)
328 {
329         curs_x = x;
330         curs_y = y;
331 }
332
333 void term_refresh_freeze(void)
334 {
335         freeze_refresh++;
336 }
337
338 void term_refresh_thaw(void)
339 {
340         if (freeze_refresh > 0) {
341                 freeze_refresh--;
342                 if (freeze_refresh == 0) term_refresh(NULL);
343         }
344 }
345
346 void term_refresh(TERM_WINDOW *window)
347 {
348         if (window != NULL)
349                 wnoutrefresh(window->win);
350
351         if (freeze_refresh == 0) {
352                 move(curs_y, curs_x);
353                 wnoutrefresh(stdscr);
354                 doupdate();
355         }
356 }
357
358 void term_stop(void)
359 {
360         term_deinit_int();
361         kill(getpid(), SIGSTOP);
362         term_init_int();
363         irssi_redraw();
364 }
365
366 int term_gets(unsigned char *buffer, int size)
367 {
368         int key, count;
369
370         for (count = 0; count < size; ) {
371                 key = getch();
372 #ifdef KEY_RESIZE
373                 if (key == KEY_RESIZE)
374                         continue;
375 #endif
376
377                 if (key == ERR)
378                         break;
379
380                 buffer[count] = key;
381                 count++;
382         }
383
384         return count;
385 }