2 term-terminfo.c : irssi
4 Copyright (C) 2001 Timo Sirainen
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.
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.
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
24 #include "terminfo-core.h"
29 /* Terminal to use for window */
32 /* Area for window in terminal */
37 TERM_WINDOW *root_window;
38 int term_width, term_height, term_detached;
40 static char *term_lines_empty; /* 1 if line is entirely empty */
41 static int vcmove, vcx, vcy, curs_visible;
42 static int crealx, crealy, cforcemove;
43 static int curs_x, curs_y;
44 static int auto_detach;
46 static int last_fg, last_bg, last_attrs;
48 static int redraw_needed, redraw_tag;
49 static int freeze_counter;
52 static void sig_cont(int p)
55 terminfo_cont(current_term);
58 static int redraw_timeout(void)
62 redraw_needed = FALSE;
72 last_fg = last_bg = -1;
74 vcx = vcy = 0; crealx = crealy = -1;
75 vcmove = FALSE; cforcemove = TRUE;
78 current_term = terminfo_core_init(stdin, stdout);
79 if (current_term == NULL)
82 /* grab CONT signal */
83 sigemptyset(&act.sa_mask);
85 act.sa_handler = sig_cont;
86 sigaction(SIGCONT, &act, NULL);
87 redraw_tag = g_timeout_add(500, (GSourceFunc) redraw_timeout, NULL);
90 term_width = current_term->width;
91 term_height = current_term->height;
92 root_window = term_window_create(0, 0, term_width, term_height);
93 term_detached = FALSE;
95 term_lines_empty = g_new0(char, term_height);
98 g_atexit(term_deinit);
102 void term_deinit(void)
104 if (current_term != NULL) {
105 g_source_remove(redraw_tag);
107 term_common_deinit();
108 terminfo_core_deinit(current_term);
113 static void term_move_real(void)
115 if (term_detached) return;
117 if (vcx != crealx || vcy != crealy || cforcemove) {
119 terminfo_set_cursor_visible(FALSE);
120 curs_visible = FALSE;
124 crealx = crealy = -1;
127 terminfo_move_relative(crealx, crealy, vcx, vcy);
128 crealx = vcx; crealy = vcy;
134 /* Cursor position is unknown - move it immediately to known position */
135 static void term_move_reset(int x, int y)
137 if (x >= term_width) x = term_width-1;
138 if (y >= term_height) y = term_height-1;
145 /* Resize terminal - if width or height is negative,
146 the new size is unknown and should be figured out somehow */
147 void term_resize(int width, int height)
149 if (width < 0 || height < 0) {
150 terminfo_resize(current_term);
151 width = current_term->width;
152 height = current_term->height;
155 if (term_width != width || term_height != height) {
156 term_width = current_term->width = width;
157 term_height = current_term->height = height;
158 term_window_move(root_window, 0, 0, term_width, term_height);
160 g_free(term_lines_empty);
161 term_lines_empty = g_new0(char, term_height);
164 term_move_reset(0, 0);
167 void term_resize_final(int width, int height)
171 /* Returns TRUE if terminal has colors */
172 int term_has_colors(void)
174 return current_term->has_colors;
177 /* Force the colors on any way you can */
178 void term_force_colors(int set)
180 if (term_detached) return;
182 terminfo_setup_colors(current_term, set);
186 void term_clear(void)
188 if (term_detached) return;
190 term_set_color(root_window, ATTR_RESET);
192 term_move_reset(0, 0);
194 memset(term_lines_empty, 1, term_height);
200 if (term_detached) return;
202 terminfo_beep(current_term);
205 /* Create a new window in terminal */
206 TERM_WINDOW *term_window_create(int x, int y, int width, int height)
210 window = g_new0(TERM_WINDOW, 1);
211 window->term = current_term;
212 window->x = x; window->y = y;
213 window->width = width; window->height = height;
217 /* Destroy a terminal window */
218 void term_window_destroy(TERM_WINDOW *window)
223 /* Move/resize a window */
224 void term_window_move(TERM_WINDOW *window, int x, int y,
225 int width, int height)
229 window->width = width;
230 window->height = height;
234 void term_window_clear(TERM_WINDOW *window)
238 if (term_detached) return;
240 terminfo_set_normal();
241 if (window->y == 0 && window->height == term_height) {
244 for (y = 0; y < window->height; y++) {
245 term_move(window, 0, y);
246 term_clrtoeol(window);
251 /* Scroll window up/down */
252 void term_window_scroll(TERM_WINDOW *window, int count)
256 if (term_detached) return;
258 terminfo_scroll(window->y, window->y+window->height-1, count);
259 term_move_reset(vcx, vcy);
261 /* set the newly scrolled area dirty */
262 for (y = 0; y < window->height; y++)
263 term_lines_empty[window->y+y] = FALSE;
266 /* Change active color */
267 void term_set_color(TERM_WINDOW *window, int col)
271 if (term_detached) return;
273 set_normal = ((col & ATTR_RESETFG) && last_fg != -1) ||
274 ((col & ATTR_RESETBG) && last_bg != -1);
275 if (((last_attrs & ATTR_BOLD) && (col & ATTR_BOLD) == 0) ||
276 ((last_attrs & ATTR_BLINK) && (col & ATTR_BLINK) == 0)) {
277 /* we'll need to get rid of bold/blink - this can only be
278 done with setting the default color */
283 last_fg = last_bg = -1;
285 terminfo_set_normal();
288 if (!term_use_colors && (col & 0xf0) != 0)
291 /* reversed text (use standout) */
292 if (col & ATTR_REVERSE) {
293 if ((last_attrs & ATTR_REVERSE) == 0)
294 terminfo_set_standout(TRUE);
295 } else if (last_attrs & ATTR_REVERSE)
296 terminfo_set_standout(FALSE);
298 /* set foreground color */
299 if ((col & 0x0f) != last_fg &&
300 ((col & 0x0f) != 0 || (col & ATTR_RESETFG) == 0)) {
301 if (term_use_colors) {
302 last_fg = col & 0x0f;
303 terminfo_set_fg(last_fg);
307 /* set background color */
308 if (col & ATTR_BLINK)
313 if ((col & 0xf0) >> 4 != last_bg &&
314 ((col & 0xf0) != 0 || (col & ATTR_RESETBG) == 0)) {
315 if (term_use_colors) {
316 last_bg = (col & 0xf0) >> 4;
317 terminfo_set_bg(last_bg);
324 else if (col & ATTR_BOLD)
328 if (col & ATTR_UNDERLINE) {
329 if ((last_attrs & ATTR_UNDERLINE) == 0)
330 terminfo_set_uline(TRUE);
331 } else if (last_attrs & ATTR_UNDERLINE)
332 terminfo_set_uline(FALSE);
334 last_attrs = col & ~0xff;
337 void term_move(TERM_WINDOW *window, int x, int y)
343 if (vcx >= term_width)
345 if (vcy >= term_height)
349 static void term_printed_text(int count)
351 term_lines_empty[vcy] = FALSE;
353 /* if we continued writing past the line, wrap to next line.
354 However, next term_move() really shouldn't try to cache
355 the move, otherwise terminals would try to combine the
356 last word in upper line with first word in lower line. */
359 while (vcx >= term_width) {
361 if (vcy < term_height) vcy++;
362 if (vcx > 0) term_lines_empty[vcy] = FALSE;
366 void term_addch(TERM_WINDOW *window, int chr)
368 if (term_detached) return;
370 if (vcmove) term_move_real();
371 term_printed_text(1);
372 if (vcy != term_height || vcx != 0)
373 putc(chr, window->term->out);
376 void term_addstr(TERM_WINDOW *window, const char *str)
380 if (term_detached) return;
382 if (vcmove) term_move_real();
384 term_printed_text(len);
386 if (vcy != term_height || vcx != 0)
387 fputs(str, window->term->out);
389 fwrite(str, 1, len-1, window->term->out);
392 void term_clrtoeol(TERM_WINDOW *window)
394 if (term_detached) return;
396 /* clrtoeol() doesn't necessarily understand colors */
397 if (last_fg == -1 && last_bg == -1 &&
398 (last_attrs & (ATTR_UNDERLINE|ATTR_REVERSE)) == 0) {
399 if (!term_lines_empty[vcy]) {
400 if (vcmove) term_move_real();
402 if (vcx == 0) term_lines_empty[vcy] = TRUE;
404 } else if (vcx < term_width) {
405 /* we'll need to fill the line ourself. */
406 if (vcmove) term_move_real();
407 terminfo_repeat(' ', term_width-vcx);
408 terminfo_move(vcx, vcy);
409 term_lines_empty[vcy] = FALSE;
413 void term_move_cursor(int x, int y)
419 void term_refresh(TERM_WINDOW *window)
421 if (term_detached || freeze_counter > 0)
424 term_move(root_window, curs_x, curs_y);
428 terminfo_set_cursor_visible(TRUE);
431 term_set_color(window, ATTR_RESET);
432 fflush(window != NULL ? window->term->out : current_term->out);
435 void term_refresh_freeze(void)
439 if (!term_detached && curs_visible) {
440 terminfo_set_cursor_visible(FALSE);
441 curs_visible = FALSE;
445 void term_refresh_thaw(void)
447 if (--freeze_counter == 0)
451 void term_auto_detach(int set)
456 void term_detach(void)
458 terminfo_stop(current_term);
460 fclose(current_term->in);
461 fclose(current_term->out);
463 current_term->in = NULL;
464 current_term->out = NULL;
465 term_detached = TRUE;
468 void term_attach(FILE *in, FILE *out)
470 current_term->in = in;
471 current_term->out = out;
472 term_detached = FALSE;
474 terminfo_cont(current_term);
481 kill(getpid(), SIGSTOP);
483 terminfo_stop(current_term);
484 kill(getpid(), SIGSTOP);
485 terminfo_cont(current_term);
490 int term_gets(unsigned char *buffer, int size)
497 /* fread() doesn't work */
498 ret = read(fileno(current_term->in), buffer, size);
500 /* EOF - terminal got lost */
504 } else if (ret == -1 && (errno == EINTR || errno == EAGAIN))