2001-10-28 06:30:26 -05:00
|
|
|
/*
|
|
|
|
term-terminfo.c : irssi
|
|
|
|
|
|
|
|
Copyright (C) 2001 Timo Sirainen
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
2007-05-08 14:41:10 -04:00
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2001-10-28 06:30:26 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "module.h"
|
|
|
|
#include "signals.h"
|
|
|
|
#include "term.h"
|
|
|
|
#include "terminfo-core.h"
|
2014-01-09 09:20:29 -05:00
|
|
|
#include "fe-windows.h"
|
2002-02-15 08:38:24 -05:00
|
|
|
#include "utf8.h"
|
2001-10-28 06:30:26 -05:00
|
|
|
|
|
|
|
#include <signal.h>
|
2014-01-09 09:20:29 -05:00
|
|
|
#include <termios.h>
|
|
|
|
#include <stdio.h>
|
2001-10-28 06:30:26 -05:00
|
|
|
|
2002-02-15 08:38:24 -05:00
|
|
|
/* returns number of characters in the beginning of the buffer being a
|
|
|
|
a single character, or -1 if more input is needed. The character will be
|
|
|
|
saved in result */
|
|
|
|
typedef int (*TERM_INPUT_FUNC)(const unsigned char *buffer, int size,
|
|
|
|
unichar *result);
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
struct _TERM_WINDOW {
|
|
|
|
/* Terminal to use for window */
|
|
|
|
TERM_REC *term;
|
|
|
|
|
|
|
|
/* Area for window in terminal */
|
|
|
|
int x, y;
|
|
|
|
int width, height;
|
|
|
|
};
|
|
|
|
|
|
|
|
TERM_WINDOW *root_window;
|
|
|
|
|
2001-12-17 18:01:12 -05:00
|
|
|
static char *term_lines_empty; /* 1 if line is entirely empty */
|
2001-11-03 10:31:13 -05:00
|
|
|
static int vcmove, vcx, vcy, curs_visible;
|
|
|
|
static int crealx, crealy, cforcemove;
|
2001-10-28 06:30:26 -05:00
|
|
|
static int curs_x, curs_y;
|
2001-12-17 18:01:12 -05:00
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
static unsigned int last_fg, last_bg;
|
|
|
|
static int last_attrs;
|
2001-12-17 18:01:12 -05:00
|
|
|
|
2009-02-27 09:20:35 -05:00
|
|
|
static GSource *sigcont_source;
|
|
|
|
static volatile sig_atomic_t got_sigcont;
|
2001-11-03 09:42:28 -05:00
|
|
|
static int freeze_counter;
|
2001-10-28 06:30:26 -05:00
|
|
|
|
2002-02-15 08:38:24 -05:00
|
|
|
static TERM_INPUT_FUNC input_func;
|
|
|
|
static unsigned char term_inbuf[256];
|
|
|
|
static int term_inbuf_pos;
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
/* SIGCONT handler */
|
|
|
|
static void sig_cont(int p)
|
|
|
|
{
|
2009-02-27 09:20:35 -05:00
|
|
|
got_sigcont = TRUE;
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2009-02-27 09:20:35 -05:00
|
|
|
/* SIGCONT GSource */
|
|
|
|
static gboolean sigcont_prepare(GSource *source, gint *timeout)
|
2001-10-28 06:30:26 -05:00
|
|
|
{
|
2009-02-27 09:20:35 -05:00
|
|
|
*timeout = -1;
|
|
|
|
return got_sigcont;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean sigcont_check(GSource *source)
|
|
|
|
{
|
|
|
|
return got_sigcont;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean sigcont_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
|
|
|
|
{
|
|
|
|
got_sigcont = FALSE;
|
|
|
|
if (callback == NULL)
|
|
|
|
return TRUE;
|
|
|
|
return callback(user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean do_redraw(gpointer unused)
|
|
|
|
{
|
|
|
|
terminfo_cont(current_term);
|
|
|
|
irssi_redraw();
|
2001-10-28 06:30:26 -05:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-02-27 09:20:35 -05:00
|
|
|
static GSourceFuncs sigcont_funcs = {
|
|
|
|
.prepare = sigcont_prepare,
|
|
|
|
.check = sigcont_check,
|
|
|
|
.dispatch = sigcont_dispatch
|
|
|
|
};
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
int term_init(void)
|
|
|
|
{
|
2002-03-14 18:46:48 -05:00
|
|
|
struct sigaction act;
|
|
|
|
int width, height;
|
2001-10-28 06:30:26 -05:00
|
|
|
|
|
|
|
last_fg = last_bg = -1;
|
2001-10-28 13:40:12 -05:00
|
|
|
last_attrs = 0;
|
2001-11-03 10:31:13 -05:00
|
|
|
vcx = vcy = 0; crealx = crealy = -1;
|
|
|
|
vcmove = FALSE; cforcemove = TRUE;
|
2001-11-03 09:42:28 -05:00
|
|
|
curs_visible = TRUE;
|
2001-10-28 06:30:26 -05:00
|
|
|
|
|
|
|
current_term = terminfo_core_init(stdin, stdout);
|
|
|
|
if (current_term == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
2002-03-14 18:46:48 -05:00
|
|
|
if (term_get_size(&width, &height)) {
|
|
|
|
current_term->width = width;
|
|
|
|
current_term->height = height;
|
|
|
|
}
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
/* grab CONT signal */
|
|
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
act.sa_flags = 0;
|
|
|
|
act.sa_handler = sig_cont;
|
|
|
|
sigaction(SIGCONT, &act, NULL);
|
2009-02-27 09:20:35 -05:00
|
|
|
sigcont_source = g_source_new(&sigcont_funcs, sizeof(GSource));
|
|
|
|
g_source_set_callback(sigcont_source, do_redraw, NULL, NULL);
|
|
|
|
g_source_attach(sigcont_source, NULL);
|
2001-10-28 06:30:26 -05:00
|
|
|
|
|
|
|
curs_x = curs_y = 0;
|
|
|
|
term_width = current_term->width;
|
|
|
|
term_height = current_term->height;
|
|
|
|
root_window = term_window_create(0, 0, term_width, term_height);
|
|
|
|
|
2001-11-03 10:31:13 -05:00
|
|
|
term_lines_empty = g_new0(char, term_height);
|
|
|
|
|
2002-02-15 08:38:24 -05:00
|
|
|
term_set_input_type(TERM_TYPE_8BIT);
|
2001-10-28 06:30:26 -05:00
|
|
|
term_common_init();
|
2014-07-06 13:56:17 -04:00
|
|
|
atexit(term_deinit);
|
2001-10-28 06:30:26 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void term_deinit(void)
|
|
|
|
{
|
2002-02-10 10:01:00 -05:00
|
|
|
if (current_term != NULL) {
|
2002-03-16 18:17:33 -05:00
|
|
|
signal(SIGCONT, SIG_DFL);
|
2009-02-27 09:20:35 -05:00
|
|
|
g_source_destroy(sigcont_source);
|
|
|
|
g_source_unref(sigcont_source);
|
2001-10-28 06:30:26 -05:00
|
|
|
|
2002-02-10 10:01:00 -05:00
|
|
|
term_common_deinit();
|
|
|
|
terminfo_core_deinit(current_term);
|
|
|
|
current_term = NULL;
|
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2001-11-03 10:31:13 -05:00
|
|
|
static void term_move_real(void)
|
|
|
|
{
|
|
|
|
if (vcx != crealx || vcy != crealy || cforcemove) {
|
|
|
|
if (curs_visible) {
|
|
|
|
terminfo_set_cursor_visible(FALSE);
|
|
|
|
curs_visible = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cforcemove) {
|
|
|
|
crealx = crealy = -1;
|
|
|
|
cforcemove = FALSE;
|
|
|
|
}
|
|
|
|
terminfo_move_relative(crealx, crealy, vcx, vcy);
|
|
|
|
crealx = vcx; crealy = vcy;
|
|
|
|
}
|
|
|
|
|
|
|
|
vcmove = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cursor position is unknown - move it immediately to known position */
|
|
|
|
static void term_move_reset(int x, int y)
|
|
|
|
{
|
|
|
|
if (x >= term_width) x = term_width-1;
|
|
|
|
if (y >= term_height) y = term_height-1;
|
|
|
|
|
|
|
|
vcx = x; vcy = y;
|
|
|
|
cforcemove = TRUE;
|
|
|
|
term_move_real();
|
|
|
|
}
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
/* Resize terminal - if width or height is negative,
|
|
|
|
the new size is unknown and should be figured out somehow */
|
|
|
|
void term_resize(int width, int height)
|
|
|
|
{
|
|
|
|
if (width < 0 || height < 0) {
|
|
|
|
width = current_term->width;
|
|
|
|
height = current_term->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (term_width != width || term_height != height) {
|
|
|
|
term_width = current_term->width = width;
|
|
|
|
term_height = current_term->height = height;
|
2001-11-03 10:31:13 -05:00
|
|
|
term_window_move(root_window, 0, 0, term_width, term_height);
|
|
|
|
|
|
|
|
g_free(term_lines_empty);
|
|
|
|
term_lines_empty = g_new0(char, term_height);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
2001-10-28 13:40:12 -05:00
|
|
|
|
2001-11-03 10:31:13 -05:00
|
|
|
term_move_reset(0, 0);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2001-10-28 16:17:34 -05:00
|
|
|
void term_resize_final(int width, int height)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
/* Returns TRUE if terminal has colors */
|
|
|
|
int term_has_colors(void)
|
|
|
|
{
|
2008-01-25 06:20:40 -05:00
|
|
|
return current_term->TI_colors > 0;
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Force the colors on any way you can */
|
|
|
|
void term_force_colors(int set)
|
|
|
|
{
|
|
|
|
terminfo_setup_colors(current_term, set);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear screen */
|
|
|
|
void term_clear(void)
|
|
|
|
{
|
2002-02-10 09:10:09 -05:00
|
|
|
term_set_color(root_window, ATTR_RESET);
|
2001-11-03 10:31:13 -05:00
|
|
|
terminfo_clear();
|
|
|
|
term_move_reset(0, 0);
|
|
|
|
|
|
|
|
memset(term_lines_empty, 1, term_height);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Beep */
|
|
|
|
void term_beep(void)
|
|
|
|
{
|
2001-10-28 13:40:12 -05:00
|
|
|
terminfo_beep(current_term);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a new window in terminal */
|
|
|
|
TERM_WINDOW *term_window_create(int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
TERM_WINDOW *window;
|
|
|
|
|
|
|
|
window = g_new0(TERM_WINDOW, 1);
|
|
|
|
window->term = current_term;
|
|
|
|
window->x = x; window->y = y;
|
|
|
|
window->width = width; window->height = height;
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy a terminal window */
|
|
|
|
void term_window_destroy(TERM_WINDOW *window)
|
|
|
|
{
|
|
|
|
g_free(window);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move/resize a window */
|
|
|
|
void term_window_move(TERM_WINDOW *window, int x, int y,
|
|
|
|
int width, int height)
|
|
|
|
{
|
|
|
|
window->x = x;
|
|
|
|
window->y = y;
|
|
|
|
window->width = width;
|
|
|
|
window->height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear window */
|
|
|
|
void term_window_clear(TERM_WINDOW *window)
|
|
|
|
{
|
|
|
|
int y;
|
|
|
|
|
|
|
|
terminfo_set_normal();
|
2001-10-29 14:13:52 -05:00
|
|
|
if (window->y == 0 && window->height == term_height) {
|
|
|
|
term_clear();
|
|
|
|
} else {
|
|
|
|
for (y = 0; y < window->height; y++) {
|
|
|
|
term_move(window, 0, y);
|
|
|
|
term_clrtoeol(window);
|
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scroll window up/down */
|
|
|
|
void term_window_scroll(TERM_WINDOW *window, int count)
|
|
|
|
{
|
2001-11-14 19:32:30 -05:00
|
|
|
int y;
|
2001-11-03 10:31:13 -05:00
|
|
|
|
|
|
|
terminfo_scroll(window->y, window->y+window->height-1, count);
|
|
|
|
term_move_reset(vcx, vcy);
|
2001-11-14 19:32:30 -05:00
|
|
|
|
|
|
|
/* set the newly scrolled area dirty */
|
2014-08-09 05:40:37 -04:00
|
|
|
for (y = 0; (window->y+y) < term_height && y < window->height; y++)
|
2001-11-14 19:32:30 -05:00
|
|
|
term_lines_empty[window->y+y] = FALSE;
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
inline static int term_putchar(int c)
|
2001-10-28 06:30:26 -05:00
|
|
|
{
|
2014-01-09 09:20:29 -05:00
|
|
|
return fputc(c, current_term->out);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copied from terminfo-core.c */
|
|
|
|
int tputs();
|
|
|
|
|
2014-07-04 06:46:51 -04:00
|
|
|
static int termctl_set_color_24bit(int bg, unsigned int lc)
|
2014-01-09 09:20:29 -05:00
|
|
|
{
|
|
|
|
static char buf[20];
|
|
|
|
const unsigned char color[] = { lc >> 16, lc >> 8, lc };
|
|
|
|
|
|
|
|
if (!term_use_colors24) {
|
|
|
|
if (bg)
|
|
|
|
terminfo_set_bg(color_24bit_256(color));
|
|
|
|
else
|
|
|
|
terminfo_set_fg(color_24bit_256(color));
|
|
|
|
return -1;
|
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
/* \e[x8;2;...;...;...m */
|
|
|
|
sprintf(buf, "\033[%d8;2;%d;%d;%dm", bg ? 4 : 3, color[0], color[1], color[2]);
|
|
|
|
return tputs(buf, 0, term_putchar);
|
|
|
|
}
|
2011-05-03 10:40:34 -04:00
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
#define COLOR_RESET UINT_MAX
|
2014-07-23 18:09:48 -04:00
|
|
|
#define COLOR_BLACK24 COLOR_RESET - 1
|
2014-01-09 09:20:29 -05:00
|
|
|
|
|
|
|
/* Change active color */
|
2014-07-04 06:46:51 -04:00
|
|
|
#ifdef TERM_TRUECOLOR
|
2014-01-09 09:20:29 -05:00
|
|
|
void term_set_color2(TERM_WINDOW *window, int col, unsigned int fgcol24, unsigned int bgcol24)
|
2014-07-04 06:46:51 -04:00
|
|
|
#else
|
|
|
|
void term_set_color(TERM_WINDOW *window, int col)
|
|
|
|
#endif
|
2014-01-09 09:20:29 -05:00
|
|
|
{
|
|
|
|
int set_normal;
|
2011-05-03 10:40:34 -04:00
|
|
|
|
2014-07-23 18:09:48 -04:00
|
|
|
unsigned int fg, bg;
|
2014-07-04 06:46:51 -04:00
|
|
|
#ifdef TERM_TRUECOLOR
|
2014-07-23 18:09:48 -04:00
|
|
|
if (col & ATTR_FGCOLOR24) {
|
|
|
|
if (fgcol24)
|
|
|
|
fg = fgcol24 << 8;
|
|
|
|
else
|
|
|
|
fg = COLOR_BLACK24;
|
|
|
|
} else
|
2014-07-04 06:46:51 -04:00
|
|
|
#endif
|
2014-07-23 18:09:48 -04:00
|
|
|
fg = (col & FG_MASK);
|
2014-07-04 06:46:51 -04:00
|
|
|
|
|
|
|
#ifdef TERM_TRUECOLOR
|
2014-07-23 18:09:48 -04:00
|
|
|
if (col & ATTR_BGCOLOR24) {
|
|
|
|
if (bgcol24)
|
|
|
|
bg = bgcol24 << 8;
|
|
|
|
else
|
|
|
|
bg = COLOR_BLACK24;
|
|
|
|
} else
|
2014-07-04 06:46:51 -04:00
|
|
|
#endif
|
2014-07-23 18:09:48 -04:00
|
|
|
bg = ((col & BG_MASK) >> BG_SHIFT);
|
2011-05-03 10:40:34 -04:00
|
|
|
|
2011-11-06 14:40:25 -05:00
|
|
|
if (!term_use_colors && bg > 0)
|
|
|
|
col |= ATTR_REVERSE;
|
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
set_normal = ((col & ATTR_RESETFG) && last_fg != COLOR_RESET) ||
|
|
|
|
((col & ATTR_RESETBG) && last_bg != COLOR_RESET);
|
|
|
|
if (((last_attrs & ATTR_BOLD) && (col & ATTR_BOLD) == 0) ||
|
2011-11-06 14:40:25 -05:00
|
|
|
((last_attrs & ATTR_REVERSE) && (col & ATTR_REVERSE) == 0) ||
|
2014-01-09 09:20:29 -05:00
|
|
|
((last_attrs & ATTR_BLINK) && (col & ATTR_BLINK) == 0)) {
|
2011-11-06 14:40:25 -05:00
|
|
|
/* we'll need to get rid of bold/blink/reverse - this
|
|
|
|
can only be done with setting the default color */
|
2001-10-28 06:30:26 -05:00
|
|
|
set_normal = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (set_normal) {
|
2014-01-09 09:20:29 -05:00
|
|
|
last_fg = last_bg = COLOR_RESET;
|
2001-10-28 06:30:26 -05:00
|
|
|
last_attrs = 0;
|
|
|
|
terminfo_set_normal();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set foreground color */
|
2014-01-09 09:20:29 -05:00
|
|
|
if (fg != last_fg &&
|
|
|
|
(fg != 0 || (col & ATTR_RESETFG) == 0)) {
|
2001-10-29 14:16:14 -05:00
|
|
|
if (term_use_colors) {
|
2008-12-05 08:55:23 -05:00
|
|
|
last_fg = fg;
|
2014-07-23 18:09:48 -04:00
|
|
|
if (fg >> 8)
|
|
|
|
termctl_set_color_24bit(0,
|
|
|
|
last_fg == COLOR_BLACK24 ? 0
|
|
|
|
: last_fg >> 8);
|
2014-01-09 09:20:29 -05:00
|
|
|
else
|
|
|
|
terminfo_set_fg(last_fg);
|
2001-10-29 14:16:14 -05:00
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set background color */
|
2014-12-14 16:21:40 -05:00
|
|
|
if (window && window->term->TI_colors &&
|
|
|
|
(term_color256map[bg&0xff]&8) == window->term->TI_colors)
|
2001-10-28 06:30:26 -05:00
|
|
|
col |= ATTR_BLINK;
|
2014-01-09 09:20:29 -05:00
|
|
|
if (col & ATTR_BLINK)
|
2008-01-24 08:39:17 -05:00
|
|
|
current_term->set_blink(current_term);
|
2001-10-28 06:30:26 -05:00
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
if (bg != last_bg &&
|
|
|
|
(bg != 0 || (col & ATTR_RESETBG) == 0)) {
|
2001-10-29 14:16:14 -05:00
|
|
|
if (term_use_colors) {
|
2008-12-05 08:55:23 -05:00
|
|
|
last_bg = bg;
|
2014-07-23 18:09:48 -04:00
|
|
|
if (bg >> 8)
|
|
|
|
termctl_set_color_24bit(1,
|
|
|
|
last_bg == COLOR_BLACK24 ? 0
|
|
|
|
: last_bg >> 8);
|
2014-01-09 09:20:29 -05:00
|
|
|
else
|
|
|
|
terminfo_set_bg(last_bg);
|
2001-10-29 14:16:14 -05:00
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2011-11-06 14:40:25 -05:00
|
|
|
/* reversed text */
|
|
|
|
if (col & ATTR_REVERSE)
|
|
|
|
terminfo_set_reverse();
|
|
|
|
|
2001-10-28 06:30:26 -05:00
|
|
|
/* bold */
|
2014-12-14 16:21:40 -05:00
|
|
|
if (window && window->term->TI_colors &&
|
|
|
|
(term_color256map[fg&0xff]&8) == window->term->TI_colors)
|
2001-10-28 06:30:26 -05:00
|
|
|
col |= ATTR_BOLD;
|
2014-01-09 09:20:29 -05:00
|
|
|
if (col & ATTR_BOLD)
|
2001-10-28 06:30:26 -05:00
|
|
|
terminfo_set_bold();
|
|
|
|
|
|
|
|
/* underline */
|
|
|
|
if (col & ATTR_UNDERLINE) {
|
2014-01-09 09:20:29 -05:00
|
|
|
if ((last_attrs & ATTR_UNDERLINE) == 0)
|
2001-10-28 06:30:26 -05:00
|
|
|
terminfo_set_uline(TRUE);
|
2014-01-09 09:20:29 -05:00
|
|
|
} else if (last_attrs & ATTR_UNDERLINE)
|
2001-10-28 06:30:26 -05:00
|
|
|
terminfo_set_uline(FALSE);
|
|
|
|
|
2011-11-06 14:40:25 -05:00
|
|
|
/* italic */
|
|
|
|
if (col & ATTR_ITALIC) {
|
|
|
|
if ((last_attrs & ATTR_ITALIC) == 0)
|
|
|
|
terminfo_set_italic(TRUE);
|
|
|
|
} else if (last_attrs & ATTR_ITALIC)
|
|
|
|
terminfo_set_italic(FALSE);
|
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
/* update the new attribute settings whilst ignoring color values. */
|
|
|
|
last_attrs = col & ~( BG_MASK | FG_MASK );
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void term_move(TERM_WINDOW *window, int x, int y)
|
|
|
|
{
|
2006-09-24 17:06:46 -04:00
|
|
|
if (x >= 0 && y >= 0) {
|
2001-11-03 10:31:13 -05:00
|
|
|
vcmove = TRUE;
|
|
|
|
vcx = x+window->x;
|
|
|
|
vcy = y+window->y;
|
|
|
|
|
|
|
|
if (vcx >= term_width)
|
|
|
|
vcx = term_width-1;
|
|
|
|
if (vcy >= term_height)
|
|
|
|
vcy = term_height-1;
|
2006-09-24 17:06:46 -04:00
|
|
|
}
|
2001-11-03 10:31:13 -05:00
|
|
|
}
|
2001-11-03 09:42:28 -05:00
|
|
|
|
2001-11-03 10:31:13 -05:00
|
|
|
static void term_printed_text(int count)
|
|
|
|
{
|
|
|
|
term_lines_empty[vcy] = FALSE;
|
|
|
|
|
|
|
|
/* if we continued writing past the line, wrap to next line.
|
|
|
|
However, next term_move() really shouldn't try to cache
|
|
|
|
the move, otherwise terminals would try to combine the
|
|
|
|
last word in upper line with first word in lower line. */
|
|
|
|
vcx += count;
|
|
|
|
while (vcx >= term_width) {
|
|
|
|
vcx -= term_width;
|
2002-05-06 00:58:47 -04:00
|
|
|
if (vcy < term_height-1) vcy++;
|
2001-11-03 10:31:13 -05:00
|
|
|
if (vcx > 0) term_lines_empty[vcy] = FALSE;
|
2001-10-28 13:40:12 -05:00
|
|
|
}
|
2002-05-12 10:48:11 -04:00
|
|
|
|
|
|
|
crealx += count;
|
|
|
|
if (crealx >= term_width)
|
|
|
|
cforcemove = TRUE;
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2008-04-04 04:41:44 -04:00
|
|
|
void term_addch(TERM_WINDOW *window, char chr)
|
2001-10-28 06:30:26 -05:00
|
|
|
{
|
2001-11-03 10:31:13 -05:00
|
|
|
if (vcmove) term_move_real();
|
2002-03-10 14:03:27 -05:00
|
|
|
|
2008-04-21 16:23:17 -04:00
|
|
|
/* With UTF-8, move cursor only if this char is either
|
|
|
|
single-byte (8. bit off) or beginning of multibyte
|
|
|
|
(7. bit off) */
|
|
|
|
if (term_type != TERM_TYPE_UTF8 ||
|
|
|
|
(chr & 0x80) == 0 || (chr & 0x40) == 0) {
|
|
|
|
term_printed_text(1);
|
|
|
|
}
|
2002-03-10 14:43:35 -05:00
|
|
|
|
2008-04-21 16:23:17 -04:00
|
|
|
putc(chr, window->term->out);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2002-02-15 08:38:24 -05:00
|
|
|
static void term_addch_utf8(TERM_WINDOW *window, unichar chr)
|
|
|
|
{
|
2002-02-17 13:05:25 -05:00
|
|
|
char buf[10];
|
2002-02-15 08:38:24 -05:00
|
|
|
int i, len;
|
|
|
|
|
2008-11-10 06:59:31 -05:00
|
|
|
len = g_unichar_to_utf8(chr, buf);
|
2002-02-15 08:38:24 -05:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
putc(buf[i], window->term->out);
|
|
|
|
}
|
|
|
|
|
|
|
|
void term_add_unichar(TERM_WINDOW *window, unichar chr)
|
|
|
|
{
|
|
|
|
if (vcmove) term_move_real();
|
|
|
|
|
|
|
|
switch (term_type) {
|
|
|
|
case TERM_TYPE_UTF8:
|
2007-05-31 09:56:35 -04:00
|
|
|
term_printed_text(unichar_isprint(chr) ? mk_wcwidth(chr) : 1);
|
2002-02-15 08:38:24 -05:00
|
|
|
term_addch_utf8(window, chr);
|
|
|
|
break;
|
|
|
|
case TERM_TYPE_BIG5:
|
2004-03-24 12:28:55 -05:00
|
|
|
if (chr > 0xff) {
|
|
|
|
term_printed_text(2);
|
|
|
|
putc((chr >> 8) & 0xff, window->term->out);
|
|
|
|
} else {
|
|
|
|
term_printed_text(1);
|
|
|
|
}
|
2002-02-15 08:38:24 -05:00
|
|
|
putc((chr & 0xff), window->term->out);
|
|
|
|
break;
|
|
|
|
default:
|
2004-03-24 12:28:55 -05:00
|
|
|
term_printed_text(1);
|
2002-02-15 08:38:24 -05:00
|
|
|
putc(chr, window->term->out);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-04 09:40:37 -05:00
|
|
|
void term_addstr(TERM_WINDOW *window, const char *str)
|
2001-10-28 06:30:26 -05:00
|
|
|
{
|
2001-12-04 09:40:37 -05:00
|
|
|
int len;
|
|
|
|
|
2001-11-03 10:31:13 -05:00
|
|
|
if (vcmove) term_move_real();
|
2004-03-24 12:28:55 -05:00
|
|
|
len = strlen(str); /* FIXME utf8 or big5 */
|
2001-12-04 09:40:37 -05:00
|
|
|
term_printed_text(len);
|
|
|
|
|
2008-04-20 06:27:32 -04:00
|
|
|
fwrite(str, 1, len, window->term->out);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void term_clrtoeol(TERM_WINDOW *window)
|
|
|
|
{
|
2001-11-03 10:31:13 -05:00
|
|
|
/* clrtoeol() doesn't necessarily understand colors */
|
2001-10-29 14:13:52 -05:00
|
|
|
if (last_fg == -1 && last_bg == -1 &&
|
2011-11-06 14:40:25 -05:00
|
|
|
(last_attrs & (ATTR_UNDERLINE|ATTR_REVERSE|ATTR_ITALIC)) == 0) {
|
2001-11-03 10:31:13 -05:00
|
|
|
if (!term_lines_empty[vcy]) {
|
|
|
|
if (vcmove) term_move_real();
|
|
|
|
terminfo_clrtoeol();
|
|
|
|
if (vcx == 0) term_lines_empty[vcy] = TRUE;
|
|
|
|
}
|
2001-10-29 14:13:52 -05:00
|
|
|
} else if (vcx < term_width) {
|
|
|
|
/* we'll need to fill the line ourself. */
|
2001-11-03 10:31:13 -05:00
|
|
|
if (vcmove) term_move_real();
|
2001-10-29 14:13:52 -05:00
|
|
|
terminfo_repeat(' ', term_width-vcx);
|
|
|
|
terminfo_move(vcx, vcy);
|
2001-11-03 10:31:13 -05:00
|
|
|
term_lines_empty[vcy] = FALSE;
|
2001-10-29 14:13:52 -05:00
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void term_move_cursor(int x, int y)
|
|
|
|
{
|
|
|
|
curs_x = x;
|
|
|
|
curs_y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
void term_refresh(TERM_WINDOW *window)
|
|
|
|
{
|
2008-04-19 11:01:16 -04:00
|
|
|
if (freeze_counter > 0)
|
2001-11-03 09:42:28 -05:00
|
|
|
return;
|
|
|
|
|
2001-11-03 10:31:13 -05:00
|
|
|
term_move(root_window, curs_x, curs_y);
|
|
|
|
term_move_real();
|
|
|
|
|
2001-11-03 09:42:28 -05:00
|
|
|
if (!curs_visible) {
|
|
|
|
terminfo_set_cursor_visible(TRUE);
|
|
|
|
curs_visible = TRUE;
|
|
|
|
}
|
2002-05-12 10:48:11 -04:00
|
|
|
|
2001-11-18 17:09:02 -05:00
|
|
|
term_set_color(window, ATTR_RESET);
|
2001-10-28 06:30:26 -05:00
|
|
|
fflush(window != NULL ? window->term->out : current_term->out);
|
|
|
|
}
|
|
|
|
|
|
|
|
void term_refresh_freeze(void)
|
|
|
|
{
|
2001-11-03 09:42:28 -05:00
|
|
|
freeze_counter++;
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void term_refresh_thaw(void)
|
|
|
|
{
|
2001-11-03 09:42:28 -05:00
|
|
|
if (--freeze_counter == 0)
|
|
|
|
term_refresh(NULL);
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|
|
|
|
|
2001-12-17 18:01:12 -05:00
|
|
|
void term_stop(void)
|
|
|
|
{
|
2008-04-21 16:23:17 -04:00
|
|
|
terminfo_stop(current_term);
|
|
|
|
kill(getpid(), SIGTSTP);
|
|
|
|
terminfo_cont(current_term);
|
|
|
|
irssi_redraw();
|
2001-12-17 18:01:12 -05:00
|
|
|
}
|
|
|
|
|
2002-02-15 08:38:24 -05:00
|
|
|
static int input_utf8(const unsigned char *buffer, int size, unichar *result)
|
|
|
|
{
|
2014-07-06 13:56:17 -04:00
|
|
|
unichar c = g_utf8_get_char_validated((char *)buffer, size);
|
2002-02-15 08:38:24 -05:00
|
|
|
|
2008-03-09 12:41:20 -04:00
|
|
|
switch (c) {
|
|
|
|
case (unichar)-1:
|
2002-02-15 08:38:24 -05:00
|
|
|
/* not UTF8 - fallback to 8bit ascii */
|
|
|
|
*result = *buffer;
|
|
|
|
return 1;
|
2008-03-09 12:41:20 -04:00
|
|
|
case (unichar)-2:
|
2002-02-15 08:38:24 -05:00
|
|
|
/* need more data */
|
|
|
|
return -1;
|
|
|
|
default:
|
2008-03-09 12:41:20 -04:00
|
|
|
*result = c;
|
|
|
|
return g_utf8_skip[*buffer];
|
2002-02-15 08:38:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int input_big5(const unsigned char *buffer, int size, unichar *result)
|
|
|
|
{
|
|
|
|
if (is_big5_hi(*buffer)) {
|
|
|
|
/* could be */
|
|
|
|
if (size == 1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (is_big5_los(buffer[1]) || is_big5_lox(buffer[1])) {
|
|
|
|
*result = buffer[1] + ((int) *buffer << 8);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*result = *buffer;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int input_8bit(const unsigned char *buffer, int size, unichar *result)
|
2001-10-28 06:30:26 -05:00
|
|
|
{
|
2002-02-15 08:38:24 -05:00
|
|
|
*result = *buffer;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void term_set_input_type(int type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case TERM_TYPE_UTF8:
|
|
|
|
input_func = input_utf8;
|
|
|
|
break;
|
|
|
|
case TERM_TYPE_BIG5:
|
|
|
|
input_func = input_big5;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
input_func = input_8bit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-27 09:57:16 -05:00
|
|
|
void term_gets(GArray *buffer, int *line_count)
|
2002-02-15 08:38:24 -05:00
|
|
|
{
|
|
|
|
int ret, i, char_len;
|
2001-11-03 08:12:15 -05:00
|
|
|
|
2001-10-28 18:47:47 -05:00
|
|
|
/* fread() doesn't work */
|
2002-02-15 08:38:24 -05:00
|
|
|
|
|
|
|
ret = read(fileno(current_term->in),
|
2008-04-16 17:14:05 -04:00
|
|
|
term_inbuf + term_inbuf_pos, sizeof(term_inbuf)-term_inbuf_pos);
|
2001-12-17 18:01:12 -05:00
|
|
|
if (ret == 0) {
|
|
|
|
/* EOF - terminal got lost */
|
|
|
|
ret = -1;
|
|
|
|
} else if (ret == -1 && (errno == EINTR || errno == EAGAIN))
|
2001-11-03 08:12:15 -05:00
|
|
|
ret = 0;
|
2008-04-16 17:14:05 -04:00
|
|
|
if (ret == -1)
|
|
|
|
signal_emit("command quit", 1, "Lost terminal");
|
2001-11-03 08:12:15 -05:00
|
|
|
|
2002-02-15 08:38:24 -05:00
|
|
|
if (ret > 0) {
|
|
|
|
/* convert input to unichars. */
|
|
|
|
term_inbuf_pos += ret;
|
|
|
|
for (i = 0; i < term_inbuf_pos; ) {
|
2008-04-16 17:14:05 -04:00
|
|
|
unichar key;
|
2002-02-15 08:38:24 -05:00
|
|
|
char_len = input_func(term_inbuf+i, term_inbuf_pos-i,
|
2008-04-16 17:14:05 -04:00
|
|
|
&key);
|
2002-02-15 08:38:24 -05:00
|
|
|
if (char_len < 0)
|
|
|
|
break;
|
2010-02-27 09:57:16 -05:00
|
|
|
g_array_append_val(buffer, key);
|
|
|
|
if (key == '\r' || key == '\n')
|
|
|
|
(*line_count)++;
|
2002-02-15 08:38:24 -05:00
|
|
|
|
|
|
|
i += char_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= term_inbuf_pos)
|
|
|
|
term_inbuf_pos = 0;
|
2002-03-09 12:54:38 -05:00
|
|
|
else if (i > 0) {
|
2004-05-14 08:25:49 -04:00
|
|
|
memmove(term_inbuf, term_inbuf+i, term_inbuf_pos-i);
|
2002-03-09 12:54:38 -05:00
|
|
|
term_inbuf_pos -= i;
|
2002-02-15 08:38:24 -05:00
|
|
|
}
|
|
|
|
}
|
2001-10-28 06:30:26 -05:00
|
|
|
}
|