irssi/src/fe-text/gui-printtext.c
Tom Feist 2d4edc5187 Initial implementation of 256 colour support for Irssi
This patch implements some 256 colour support for Irssi up from the
previous 16 colours. Initial parsing of the %x/%X format codes is
implemented and the parser accounts in advances the char* for
that.

The colour attributes are widened from 4 to 8 bit. The colour protocol
is changed to a new format. Some pointers to remaining work are
written in the comment in textbuffer.h.

Note that Irssi already does support requesting 256 colours from the
terminal in the original source code, so this part did not have to be
touched.
2014-06-30 00:54:16 +02:00

308 lines
8.5 KiB
C

/*
gui-printtext.c : irssi
Copyright (C) 1999 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.
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.
*/
#include "module.h"
#include "signals.h"
#include "settings.h"
#include "formats.h"
#include "printtext.h"
#include "term.h"
#include "gui-printtext.h"
#include "gui-windows.h"
int mirc_colors[] = { 15, 0, 1, 2, 12, 4, 5, 6, 14, 10, 3, 11, 9, 13, 8, 7 };
static int scrollback_lines, scrollback_time, scrollback_burst_remove;
static int next_xpos, next_ypos;
static GHashTable *indent_functions;
static INDENT_FUNC default_indent_func;
void gui_register_indent_func(const char *name, INDENT_FUNC func)
{
gpointer key, value;
GSList *list;
if (g_hash_table_lookup_extended(indent_functions, name, &key, &value)) {
list = value;
g_hash_table_remove(indent_functions, key);
} else {
key = g_strdup(name);
list = NULL;
}
list = g_slist_append(list, (void *) func);
g_hash_table_insert(indent_functions, key, list);
}
void gui_unregister_indent_func(const char *name, INDENT_FUNC func)
{
gpointer key, value;
GSList *list;
if (g_hash_table_lookup_extended(indent_functions, name, &key, &value)) {
list = value;
list = g_slist_remove(list, (void *) func);
g_hash_table_remove(indent_functions, key);
if (list == NULL)
g_free(key);
else
g_hash_table_insert(indent_functions, key, list);
}
if (default_indent_func == func)
gui_set_default_indent(NULL);
textbuffer_views_unregister_indent_func(func);
}
void gui_set_default_indent(const char *name)
{
GSList *list;
list = name == NULL ? NULL :
g_hash_table_lookup(indent_functions, name);
default_indent_func = list == NULL ? NULL :
(INDENT_FUNC) list->data;
gui_windows_reset_settings();
}
INDENT_FUNC get_default_indent_func(void)
{
return default_indent_func;
}
void gui_printtext(int xpos, int ypos, const char *str)
{
next_xpos = xpos;
next_ypos = ypos;
printtext_gui(str);
next_xpos = next_ypos = -1;
}
void gui_printtext_after_time(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str, time_t time)
{
GUI_WINDOW_REC *gui;
gui = WINDOW_GUI(dest->window);
gui->use_insert_after = TRUE;
gui->insert_after = prev;
gui->insert_after_time = time;
format_send_to_gui(dest, str);
gui->use_insert_after = FALSE;
}
void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str)
{
gui_printtext_after_time(dest, prev, str, 0);
}
static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
{
LINE_REC *line;
time_t old_time;
old_time = time(NULL)-scrollback_time+1;
if (view->buffer->lines_count >=
scrollback_lines+scrollback_burst_remove) {
/* remove lines by line count */
while (view->buffer->lines_count > scrollback_lines) {
line = view->buffer->first_line;
if (line->info.time >= old_time ||
scrollback_lines == 0) {
/* too new line, don't remove yet - also
if scrollback_lines is 0, we want to check
only scrollback_time setting. */
break;
}
textbuffer_view_remove_line(view, line);
}
}
}
static void get_colors(int flags, int *fg, int *bg, int *attr)
{
if (flags & GUI_PRINT_FLAG_MIRC_COLOR) {
g_message( "getcolor: handling mirc colors\n");
/* mirc colors - real range is 0..15, but after 16
colors wrap to 0, 1, ... */
if (*bg >= 0) *bg = mirc_colors[*bg % 16];
if (*fg >= 0) *fg = mirc_colors[*fg % 16];
/* TODO: What to do here? */
if (settings_get_bool("mirc_blink_fix"))
*bg &= ~0x08;
}
if (*fg < 0 || *fg > 255) {
g_message( "getcolor: fg %d outside range, setting to -1\n", *fg);
*fg = -1;
}
if (*bg < 0 || *bg > 255) {
g_message( "getcolor: bf %d outside range, setting to -1\n", *bg);
*bg = -1;
}
*attr = 0;
if (flags & GUI_PRINT_FLAG_REVERSE) {
*attr |= ATTR_REVERSE;
g_message( "getcolor: setting flag_reverse\n");
}
if (flags & GUI_PRINT_FLAG_BOLD) {
*attr |= ATTR_BOLD;
g_message( "getcolor: setting flag_bold\n");
}
if (flags & GUI_PRINT_FLAG_UNDERLINE) {
*attr |= ATTR_UNDERLINE;
g_message( "getcolor: setting flag_underline\n");
}
if (flags & GUI_PRINT_FLAG_BLINK) {
*attr |= ATTR_BLINK;
g_message( "getcolor: setting flag_blink\n");
}
}
static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line)
{
static const unsigned char eol[] = { 0, LINE_CMD_EOL };
*line = textbuffer_insert(view->buffer, *line, eol, 2, NULL);
textbuffer_view_insert_line(view, *line);
}
static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
void *bgcolor, void *pflags,
char *str, TEXT_DEST_REC *dest)
{
GUI_WINDOW_REC *gui;
TEXT_BUFFER_VIEW_REC *view;
LINE_REC *insert_after;
LINE_INFO_REC lineinfo;
int fg, bg, flags, attr;
attr = 0;
flags = GPOINTER_TO_INT(pflags);
fg = GPOINTER_TO_INT(fgcolor);
bg = GPOINTER_TO_INT(bgcolor);
g_message( "SGPT str: '%s'\n", str);
g_message( "SGPT start: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x), flags: %d (0x%04x)\n",
fg, fg, bg, bg, attr, attr, flags, flags);
get_colors(flags, &fg, &bg, &attr);
g_message( "SGPT getcol: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x)\n",
fg, fg, (bg << 8), (bg << 8), attr, attr);
if (window == NULL) {
g_return_if_fail(next_xpos != -1);
attr |= fg >= 0 ? fg : ATTR_RESETFG;
attr |= bg >= 0 ? (bg << 8) : ATTR_RESETBG;
g_message(
"SGPT nowin: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x)\n",
fg, fg, (bg << 8), (bg << 8), attr, attr);
term_set_color(root_window, attr);
term_move(root_window, next_xpos, next_ypos);
if (flags & GUI_PRINT_FLAG_CLRTOEOL)
term_clrtoeol(root_window);
term_addstr(root_window, str);
next_xpos += strlen(str); /* FIXME utf8 or big5 */
return;
}
lineinfo.level = dest == NULL ? 0 : dest->level;
gui = WINDOW_GUI(window);
lineinfo.time = (gui->use_insert_after && gui->insert_after_time) ?
gui->insert_after_time : time(NULL);
view = gui->view;
insert_after = gui->use_insert_after ?
gui->insert_after : view->buffer->cur_line;
if (flags & GUI_PRINT_FLAG_NEWLINE) {
view_add_eol(view, &insert_after);
}
textbuffer_line_add_colors(view->buffer, &insert_after, fg, bg, flags);
insert_after = textbuffer_insert(view->buffer, insert_after,
(unsigned char *) str,
strlen(str), &lineinfo);
if (gui->use_insert_after)
gui->insert_after = insert_after;
}
static void sig_gui_printtext_finished(WINDOW_REC *window)
{
TEXT_BUFFER_VIEW_REC *view;
LINE_REC *insert_after;
view = WINDOW_GUI(window)->view;
insert_after = WINDOW_GUI(window)->use_insert_after ?
WINDOW_GUI(window)->insert_after : view->buffer->cur_line;
view_add_eol(view, &insert_after);
remove_old_lines(view);
}
static void read_settings(void)
{
scrollback_lines = settings_get_int("scrollback_lines");
scrollback_time = settings_get_time("scrollback_time")/1000;
scrollback_burst_remove = settings_get_int("scrollback_burst_remove");
}
void gui_printtext_init(void)
{
next_xpos = next_ypos = -1;
default_indent_func = NULL;
indent_functions = g_hash_table_new((GHashFunc) g_str_hash,
(GCompareFunc) g_str_equal);
settings_add_int("history", "scrollback_lines", 500);
settings_add_time("history", "scrollback_time", "1day");
settings_add_int("history", "scrollback_burst_remove", 10);
signal_add("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
signal_add("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
read_settings();
}
void gui_printtext_deinit(void)
{
g_hash_table_destroy(indent_functions);
signal_remove("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}