irssi/src/fe-text/gui-printtext.c
Timo Sirainen ae25925a1f Some logging fixes. Flood checking had a memory leak. Query had a small
memory leak. Text buffer fixes.


git-svn-id: http://svn.irssi.org/repos/irssi/trunk@226 dbcabf3a-b0e7-0310-adc4-f8d773084564
2000-05-18 08:46:56 +00:00

343 lines
8.7 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "module.h"
#include "signals.h"
#include "commands.h"
#include "settings.h"
#include "printtext.h"
#include "windows.h"
#include "themes.h"
#include "screen.h"
#include "gui-windows.h"
#define TEXT_CHUNK_USABLE_SIZE (LINE_TEXT_CHUNK_SIZE-2-sizeof(char*))
static gint mirc_colors[] = { 15, 0, 1, 2, 4, 6, 5, 4, 14, 10, 3, 11, 9, 13, 8, 7, 15 };
static gint max_textwidget_lines;
#define mark_temp_eol(text) \
memcpy((text)->buffer + (text)->pos, "\0\x80", 2);
static LINE_REC *create_line(GUI_WINDOW_REC *gui, int level)
{
g_return_val_if_fail(gui != NULL, NULL);
g_return_val_if_fail(gui->cur_text != NULL, NULL);
gui->cur_line = g_mem_chunk_alloc(gui->line_chunk);
gui->cur_line->text = gui->cur_text->buffer+gui->cur_text->pos;
gui->cur_line->level = GPOINTER_TO_INT(level);
gui->cur_line->time = time(NULL);
mark_temp_eol(gui->cur_text);
gui->last_color = -1;
gui->last_flags = 0;
gui->lines = g_list_append(gui->lines, gui->cur_line);
if (gui->startline == NULL) {
/* first line */
gui->startline = gui->lines;
gui->bottom_startline = gui->lines;
}
return gui->cur_line;
}
static TEXT_CHUNK_REC *create_text_chunk(GUI_WINDOW_REC *gui)
{
TEXT_CHUNK_REC *rec;
char *buffer, *ptr;
g_return_val_if_fail(gui != NULL, NULL);
rec = g_new(TEXT_CHUNK_REC, 1);
rec->overflow[0] = 0;
rec->overflow[1] = (char) LINE_CMD_OVERFLOW;
rec->pos = 0;
rec->lines = 0;
if (gui->cur_line != NULL && gui->cur_line->text != NULL) {
/* create a link to new block from the old block */
buffer = gui->cur_text->buffer + gui->cur_text->pos;
*buffer++ = 0; *buffer++ = (char) LINE_CMD_CONTINUE;
ptr = rec->buffer;
memcpy(buffer, &ptr, sizeof(char *));
}
gui->cur_text = rec;
gui->text_chunks = g_slist_append(gui->text_chunks, rec);
return rec;
}
static void text_chunk_free(GUI_WINDOW_REC *gui, TEXT_CHUNK_REC *chunk)
{
g_return_if_fail(gui != NULL);
g_return_if_fail(chunk != NULL);
gui->text_chunks = g_slist_remove(gui->text_chunks, chunk);
g_free(chunk);
}
static void remove_first_line(WINDOW_REC *window)
{
GUI_WINDOW_REC *gui;
TEXT_CHUNK_REC *chunk;
g_return_if_fail(window != NULL);
gui = WINDOW_GUI(window);
chunk = gui->text_chunks->data;
if (--chunk->lines == 0)
text_chunk_free(gui, chunk);
if (gui->startline->prev == NULL) {
/* first line in screen removed */
gui->startline = gui->startline->next;
gui->subline = 0;
}
if (gui->bottom_startline->prev == NULL) {
/* bottom line removed (shouldn't happen?) */
gui->bottom_startline = gui->bottom_startline->next;
gui->bottom_subline = 0;
}
window->lines--;
g_mem_chunk_free(gui->line_chunk, gui->lines->data);
gui->lines = g_list_remove(gui->lines, gui->lines->data);
if (gui->startline->prev == NULL && is_window_visible(window))
gui_window_redraw(window);
}
static void get_colors(int flags, int *fg, int *bg)
{
if (flags & PRINTFLAG_MIRC_COLOR) {
/* mirc colors */
*fg = *fg < 0 || *fg > 16 ?
current_theme->default_color : mirc_colors[*fg];
*bg = *bg < 0 || *bg > 16 ? 0 : mirc_colors[*bg];
} else {
/* default colors */
*fg = *fg < 0 || *fg > 15 ?
current_theme->default_color : *fg;
*bg = *bg < 0 || *bg > 15 ? 0 : *bg;
if (*fg > 8) *fg -= 8;
}
if (flags & PRINTFLAG_REVERSE) {
int tmp;
tmp = *fg; *fg = *bg; *bg = tmp;
}
if (*fg == 8) *fg |= ATTR_COLOR8;
if (flags & PRINTFLAG_BOLD) *fg |= 8;
if (flags & PRINTFLAG_UNDERLINE) *fg |= ATTR_UNDERLINE;
if (flags & PRINTFLAG_BLINK) *bg |= 0x80;
}
static void linebuf_add(GUI_WINDOW_REC *gui, char *str, int len)
{
int left;
if (len == 0) return;
while (gui->cur_text->pos + len >= TEXT_CHUNK_USABLE_SIZE) {
left = TEXT_CHUNK_USABLE_SIZE - gui->cur_text->pos;
if (str[left-1] == 0) left--; /* don't split the commands */
memcpy(gui->cur_text->buffer + gui->cur_text->pos, str, left);
gui->cur_text->pos += left;
create_text_chunk(gui);
len -= left; str += left;
}
memcpy(gui->cur_text->buffer + gui->cur_text->pos, str, len);
gui->cur_text->pos += len;
}
static void line_add_colors(GUI_WINDOW_REC *gui, int fg, int bg, int flags)
{
unsigned char buffer[12];
int color, pos;
color = (fg & 0x0f) | (bg << 4);
pos = 0;
if (((fg & ATTR_COLOR8) == 0 && (fg|(bg << 4)) != gui->last_color) ||
((fg & ATTR_COLOR8) && (fg & 0xf0) != (gui->last_color & 0xf0))) {
buffer[pos++] = 0;
buffer[pos++] = color;
}
if ((flags & PRINTFLAG_UNDERLINE) != (gui->last_flags & PRINTFLAG_UNDERLINE)) {
buffer[pos++] = 0;
buffer[pos++] = LINE_CMD_UNDERLINE;
}
if (fg & ATTR_COLOR8) {
buffer[pos++] = 0;
buffer[pos++] = LINE_CMD_COLOR8;
}
if (flags & PRINTFLAG_BEEP) {
buffer[pos++] = 0;
buffer[pos++] = LINE_CMD_BEEP;
}
if (flags & PRINTFLAG_INDENT) {
buffer[pos++] = 0;
buffer[pos++] = LINE_CMD_INDENT;
}
linebuf_add(gui, (char *) buffer, pos);
gui->last_flags = flags;
gui->last_color = fg | (bg << 4);
}
static void gui_printtext(WINDOW_REC *window, gpointer fgcolor, gpointer bgcolor, gpointer pflags, char *str, gpointer level)
{
GUI_WINDOW_REC *gui;
LINE_REC *line;
int fg, bg, flags, new_lines, n, visible, ypos, subline;
g_return_if_fail(window != NULL);
gui = WINDOW_GUI(window);
if (max_textwidget_lines > 0 && max_textwidget_lines <= window->lines)
remove_first_line(window);
visible = is_window_visible(window) && gui->bottom;
flags = GPOINTER_TO_INT(pflags);
fg = GPOINTER_TO_INT(fgcolor);
bg = GPOINTER_TO_INT(bgcolor);
if (gui->cur_text == NULL)
create_text_chunk(gui);
/* \n can be only at the start of the line.. */
if (*str == '\n') {
str++;
linebuf_add(gui, "\0\x80", 2); /* mark EOL */
line = create_line(gui, 0);
gui_window_newline(gui, visible);
gui->cur_text->lines++;
gui->last_subline = 0;
} else {
line = gui->cur_line != NULL ? gui->cur_line :
create_line(gui, 0);
if (line->level == 0) line->level = GPOINTER_TO_INT(level);
}
get_colors(flags, &fg, &bg);
line_add_colors(gui, fg, bg, flags);
linebuf_add(gui, str, strlen(str));
mark_temp_eol(gui->cur_text);
gui_window_cache_remove(gui, line);
new_lines = gui_window_get_linecount(gui, line)-1 - gui->last_subline;
for (n = 0; n < new_lines; n++)
gui_window_newline(gui, visible);
if (visible) {
/* draw the line to screen. */
ypos = gui->ypos-new_lines;
if (new_lines > 0) {
set_color(0);
move(gui->parent->first_line+ypos, 0); clrtoeol();
}
if (ypos >= 0)
subline = gui->last_subline;
else {
/* *LONG* line - longer than screen height */
subline = -ypos+gui->last_subline;
ypos = 0;
}
ypos += gui->parent->first_line;
gui_window_line_draw(gui, line, ypos, subline, -1);
}
gui->last_subline += new_lines;
}
static void window_clear(GUI_WINDOW_REC *gui)
{
int n;
for (n = gui->parent->first_line; n <= gui->parent->last_line; n++) {
move(n, 0);
clrtoeol();
}
screen_refresh();
}
static void cmd_clear(void)
{
GUI_WINDOW_REC *gui;
gui = WINDOW_GUI(active_win);
if (is_window_visible(active_win))
window_clear(gui);
gui->ypos = -1;
gui->bottom_startline = gui->startline = g_list_last(gui->lines);
gui->bottom_subline = gui->subline = gui->last_subline+1;
gui->empty_linecount = gui->parent->last_line-gui->parent->first_line+1;
gui->bottom = TRUE;
}
static void sig_printtext_finished(WINDOW_REC *window)
{
if (is_window_visible(window))
screen_refresh();
}
static void read_settings(void)
{
max_textwidget_lines = settings_get_int("max_textwidget_lines");
}
void gui_printtext_init(void)
{
signal_add("gui print text", (SIGNAL_FUNC) gui_printtext);
signal_add("print text finished", (SIGNAL_FUNC) sig_printtext_finished);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
command_bind("clear", NULL, (SIGNAL_FUNC) cmd_clear);
read_settings();
}
void gui_printtext_deinit(void)
{
signal_remove("gui print text", (SIGNAL_FUNC) gui_printtext);
signal_remove("print text finished", (SIGNAL_FUNC) sig_printtext_finished);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
command_unbind("clear", (SIGNAL_FUNC) cmd_clear);
}