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