diff options
author | Timo Sirainen <cras@irssi.org> | 2000-11-21 03:00:05 +0000 |
---|---|---|
committer | cras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564> | 2000-11-21 03:00:05 +0000 |
commit | e923b1651afc995cf75caf7c63cdf8b246272801 (patch) | |
tree | e640425514a26d764587d574bfe2335dfdde4538 /src/fe-text | |
parent | e3084d3ffae3e57ddf89507e69f61b83c5ceaf90 (diff) | |
download | irssi-e923b1651afc995cf75caf7c63cdf8b246272801.zip |
/SCROLLBACK REDRAW - redraw the contents of current window according to
active formats, ie. changing theme changes scrollback.
It's still a bit buggy (can crash) with multiline formats, need to fix
it as soon as I figure out where the problem is..
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@852 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/fe-text')
-rw-r--r-- | src/fe-text/gui-printtext.c | 138 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.h | 5 | ||||
-rw-r--r-- | src/fe-text/gui-textwidget.c | 20 | ||||
-rw-r--r-- | src/fe-text/gui-windows.c | 178 | ||||
-rw-r--r-- | src/fe-text/gui-windows.h | 11 |
5 files changed, 313 insertions, 39 deletions
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c index afc960c0..3a206843 100644 --- a/src/fe-text/gui-printtext.c +++ b/src/fe-text/gui-printtext.c @@ -44,26 +44,35 @@ static GString *format; static LINE_REC *create_line(GUI_WINDOW_REC *gui, int level) { + LINE_REC *rec; + 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); + rec = g_mem_chunk_alloc(gui->line_chunk); + rec->text = gui->cur_text->buffer+gui->cur_text->pos; + rec->level = GPOINTER_TO_INT(level); + rec->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; + if (gui->temp_line != NULL) { + int pos = g_list_index(gui->lines, gui->temp_line); + gui->lines = g_list_insert(gui->lines, rec, pos+1); + gui->temp_line = rec; + } else { + gui->cur_line = rec; + gui->lines = g_list_append(gui->lines, rec); + if (gui->startline == NULL) { + /* first line */ + gui->startline = gui->lines; + gui->bottom_startline = gui->lines; + } } - return gui->cur_line; + return rec; } static TEXT_CHUNK_REC *create_text_chunk(GUI_WINDOW_REC *gui) @@ -74,8 +83,6 @@ static TEXT_CHUNK_REC *create_text_chunk(GUI_WINDOW_REC *gui) 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; @@ -105,24 +112,73 @@ static void text_chunk_free(GUI_WINDOW_REC *gui, TEXT_CHUNK_REC *chunk) g_free(chunk); } -static void remove_first_line(WINDOW_REC *window) +static TEXT_CHUNK_REC *text_chunk_find(GUI_WINDOW_REC *gui, const char *data) +{ + GSList *tmp; + + for (tmp = gui->text_chunks; tmp != NULL; tmp = tmp->next) { + TEXT_CHUNK_REC *rec = tmp->data; + + if (data >= rec->buffer && + data < rec->buffer+sizeof(rec->buffer)) + return rec; + } + + return NULL; +} + +void gui_window_line_text_free(GUI_WINDOW_REC *gui, LINE_REC *line) { - GUI_WINDOW_REC *gui; TEXT_CHUNK_REC *chunk; + const unsigned char *text; - g_return_if_fail(window != NULL); + text = line->text; + for (;;) { + if (*text == '\0') { + text++; + if (*text == LINE_CMD_EOL) + break; - gui = WINDOW_GUI(window); - chunk = gui->text_chunks->data; + if (*text == LINE_CMD_CONTINUE) { + unsigned char *tmp; + memcpy(&tmp, text+1, sizeof(char *)); + + /* free the previous block */ + chunk = text_chunk_find(gui, text); + if (--chunk->lines == 0) + text_chunk_free(gui, chunk); + + text = tmp; + continue; + } + if (*text & 0x80) + text++; + } + + text++; + } + + /* free the last block */ + chunk = text_chunk_find(gui, text); if (--chunk->lines == 0) text_chunk_free(gui, chunk); +} +void gui_window_line_remove(WINDOW_REC *window, LINE_REC *line) +{ + GUI_WINDOW_REC *gui; + + g_return_if_fail(window != NULL); + + gui = WINDOW_GUI(window); + + gui_window_line_text_free(gui, line); if (gui->lastlog_last_check != NULL && - gui->lastlog_last_check->data == window) + gui->lastlog_last_check->data == line) gui->lastlog_last_check = NULL; if (gui->lastlog_last_away != NULL && - gui->lastlog_last_away->data == window) + gui->lastlog_last_away->data == line) gui->lastlog_last_away = NULL; if (gui->startline->prev == NULL) { @@ -138,8 +194,8 @@ static void remove_first_line(WINDOW_REC *window) } window->lines--; - g_mem_chunk_free(gui->line_chunk, gui->lines->data); - gui->lines = g_list_remove(gui->lines, gui->lines->data); + g_mem_chunk_free(gui->line_chunk, line); + gui->lines = g_list_remove(gui->lines, line); if (gui->startline->prev == NULL && is_window_visible(window)) gui_window_redraw(window); @@ -162,7 +218,7 @@ static void remove_old_lines(WINDOW_REC *window) /* too new line, don't remove yet */ break; } - remove_first_line(window); + gui_window_line_remove(window, line); } } } @@ -212,6 +268,7 @@ static void linebuf_add(GUI_WINDOW_REC *gui, const char *str, int len) gui->cur_text->pos += left; create_text_chunk(gui); + gui->cur_text->lines++; len -= left; str += left; } @@ -219,6 +276,12 @@ static void linebuf_add(GUI_WINDOW_REC *gui, const char *str, int len) gui->cur_text->pos += len; } +void gui_window_line_append(GUI_WINDOW_REC *gui, const char *str, int len) +{ + linebuf_add(gui, str, len); + mark_temp_eol(gui->cur_text); +} + static void line_add_colors(GUI_WINDOW_REC *gui, int fg, int bg, int flags) { unsigned char buffer[12]; @@ -282,15 +345,26 @@ static void gui_printtext(WINDOW_REC *window, void *fgcolor, void *bgcolor, /* newline can be only at the start of the line.. */ if (flags & PRINTFLAG_NEWLINE) { - linebuf_add(gui, "\0\200", 2); /* mark EOL */ + if (!gui->eol_marked) { + if (format->len > 0 || gui->temp_line != NULL) { + /* mark format continuing to next line */ + char tmp[2] = { 0, (char)LINE_CMD_FORMAT_CONT }; + linebuf_add(gui, tmp, 2); + } + linebuf_add(gui, "\0\200", 2); /* mark EOL */ + } + gui->eol_marked = FALSE; line = create_line(gui, 0); - gui_window_newline(gui, visible); + gui_window_newline(gui, visible && gui->temp_line == NULL); gui->cur_text->lines++; gui->last_subline = 0; } else { - line = gui->cur_line != NULL ? gui->cur_line : + if (gui->eol_marked) + g_warning("gui_printtext(): eol_marked"); + line = gui->temp_line != NULL ? gui->temp_line : + gui->cur_line != NULL ? gui->cur_line : create_line(gui, 0); if (line->level == 0) line->level = GPOINTER_TO_INT(level); } @@ -301,6 +375,13 @@ static void gui_printtext(WINDOW_REC *window, void *fgcolor, void *bgcolor, mark_temp_eol(gui->cur_text); gui_window_cache_remove(gui, line); + + if (gui->temp_line != NULL) { + /* updating existing line - don't even + try to print it to screen */ + return; + } + new_lines = gui_window_get_linecount(gui, line)-1 - gui->last_subline; for (n = 0; n < new_lines; n++) @@ -376,11 +457,13 @@ static void sig_printtext_finished(WINDOW_REC *window) if (format->len > 0) { /* save format of the line */ linebuf_add(gui, format->str, format->len); - mark_temp_eol(gui->cur_text); g_string_truncate(format, 0); } + linebuf_add(gui, "\0\200", 2); /* mark EOL */ + gui->eol_marked = TRUE; + if (is_window_visible(window)) { #ifdef USE_CURSES_WINDOWS screen_refresh(gui->parent->curses_win); @@ -410,9 +493,10 @@ static void sig_print_format(THEME_REC *theme, const char *module, g_string_append_c(format, (char)LINE_CMD_FORMAT); g_string_append(format, module); - g_string_append_c(format, '\0'); + g_string_append_c(format, '\0'); g_string_append_c(format, (char)LINE_CMD_FORMAT); + g_string_append(format, formats[formatnum].tag); for (n = 0; n < formats[formatnum].params; n++) { diff --git a/src/fe-text/gui-printtext.h b/src/fe-text/gui-printtext.h index aeeb5cce..97d20e12 100644 --- a/src/fe-text/gui-printtext.h +++ b/src/fe-text/gui-printtext.h @@ -1,6 +1,8 @@ #ifndef __GUI_PRINTTEXT_H #define __GUI_PRINTTEXT_H +#include "gui-windows.h" + enum { BLACK = 0, @@ -27,4 +29,7 @@ extern int mirc_colors[]; void gui_printtext_init(void); void gui_printtext_deinit(void); +void gui_window_line_append(GUI_WINDOW_REC *gui, const char *str, int len); +void gui_window_line_remove(WINDOW_REC *window, LINE_REC *line); + #endif diff --git a/src/fe-text/gui-textwidget.c b/src/fe-text/gui-textwidget.c index 67f35882..b3527eac 100644 --- a/src/fe-text/gui-textwidget.c +++ b/src/fe-text/gui-textwidget.c @@ -417,6 +417,24 @@ static void cmd_scrollback_end(const char *data) signal_emit("gui page scrolled", 1, active_win); } +/* SYNTAX: SCROLLBACK REDRAW */ +static void cmd_scrollback_redraw(void) +{ + GUI_WINDOW_REC *gui; + GList *tmp, *next; + + gui = WINDOW_GUI(active_win); + + screen_refresh_freeze(); + for (tmp = gui->lines; tmp != NULL; tmp = next) { + next = tmp->next; + gui_window_reformat_line(active_win, tmp->data); + } + + gui_window_redraw(active_win); + screen_refresh_thaw(); +} + static void sig_away_changed(IRC_SERVER_REC *server) { GSList *tmp; @@ -440,6 +458,7 @@ void gui_textwidget_init(void) command_bind("scrollback goto", NULL, (SIGNAL_FUNC) cmd_scrollback_goto); command_bind("scrollback home", NULL, (SIGNAL_FUNC) cmd_scrollback_home); command_bind("scrollback end", NULL, (SIGNAL_FUNC) cmd_scrollback_end); + command_bind("scrollback redraw", NULL, (SIGNAL_FUNC) cmd_scrollback_redraw); command_set_options("lastlog", "!- new away word regexp"); signal_add("away mode changed", (SIGNAL_FUNC) sig_away_changed); @@ -453,6 +472,7 @@ void gui_textwidget_deinit(void) command_unbind("scrollback goto", (SIGNAL_FUNC) cmd_scrollback_goto); command_unbind("scrollback home", (SIGNAL_FUNC) cmd_scrollback_home); command_unbind("scrollback end", (SIGNAL_FUNC) cmd_scrollback_end); + command_unbind("scrollback redraw", (SIGNAL_FUNC) cmd_scrollback_redraw); signal_remove("away mode changed", (SIGNAL_FUNC) sig_away_changed); } diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index acc2c2f3..3021485b 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -20,7 +20,6 @@ #include "module.h" #include "signals.h" -#include "commands.h" #include "servers.h" #include "misc.h" #include "settings.h" @@ -28,10 +27,12 @@ #include "irc.h" #include "channels.h" #include "fe-windows.h" +#include "formats.h" #include "screen.h" #include "gui-entry.h" #include "gui-windows.h" +#include "gui-printtext.h" #ifdef HAVE_REGEX_H # include <regex.h> @@ -294,8 +295,6 @@ static LINE_CACHE_REC *gui_window_line_cache(GUI_WINDOW_REC *gui, /* set color */ color = (color & ATTR_UNDERLINE) | *ptr; } else switch (*ptr) { - case LINE_CMD_OVERFLOW: - g_error("buffer overflow! (cache)"); case LINE_CMD_UNDERLINE: color ^= ATTR_UNDERLINE; break; @@ -444,8 +443,6 @@ static void single_line_draw(GUI_WINDOW_REC *gui, int ypos, text = tmp; continue; } else switch ((unsigned char) *text) { - case LINE_CMD_OVERFLOW: - g_error("buffer overflow! (draw)"); case LINE_CMD_EOL: case LINE_CMD_FORMAT: return; @@ -790,8 +787,6 @@ GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, i else if ((guchar) *ptr == LINE_CMD_EOL || (guchar) *ptr == LINE_CMD_FORMAT) break; - else if ((guchar) *ptr == LINE_CMD_OVERFLOW) - g_error("buffer overflow! (find)"); } } str[n] = '\0'; @@ -899,6 +894,175 @@ static int sig_check_linecache(void) return 1; } +static char *line_read_format(unsigned const char **text) +{ + GString *str; + char *ret; + + str = g_string_new(NULL); + for (;;) { + if (**text == '\0') { + if ((*text)[1] == LINE_CMD_EOL) { + /* leave text at \0<eof> */ + break; + } + if ((*text)[1] == LINE_CMD_FORMAT_CONT) { + /* leave text at \0<format_cont> */ + break; + } + (*text)++; + + if (**text == LINE_CMD_FORMAT) { + /* move text to start after \0<format> */ + (*text)++; + break; + } + + if (**text == LINE_CMD_CONTINUE) { + unsigned char *tmp; + + memcpy(&tmp, (*text)+1, sizeof(char *)); + *text = tmp; + continue; + } else if (**text & 0x80) + (*text)++; + } + + g_string_append_c(str, (char) **text); + (*text)++; + } + + ret = str->str; + g_string_free(str, FALSE); + return ret; +} + +static char *gui_window_line_get_format(WINDOW_REC *window, LINE_REC *line, + GString *raw) +{ + const unsigned char *text; + char *module, *format_name, *args[MAX_FORMAT_PARAMS], *ret; + TEXT_DEST_REC dest; + int formatnum, argcount; + + text = line->text; + + /* skip the beginning of the line until we find the format */ + g_free(line_read_format(&text)); + if (text[1] == LINE_CMD_FORMAT_CONT) { + g_string_append_c(raw, '\0'); + g_string_append_c(raw, (char)LINE_CMD_FORMAT_CONT); + return NULL; + } + + /* read format information */ + module = line_read_format(&text); + format_name = line_read_format(&text); + + if (raw != NULL) { + g_string_append_c(raw, '\0'); + g_string_append_c(raw, (char)LINE_CMD_FORMAT); + + g_string_append(raw, module); + + g_string_append_c(raw, '\0'); + g_string_append_c(raw, (char)LINE_CMD_FORMAT); + + g_string_append(raw, format_name); + } + + formatnum = format_find_tag(module, format_name); + if (formatnum == -1) + ret = NULL; + else { + THEME_REC *theme; + + theme = window->theme == NULL ? current_theme : + window->theme; + + argcount = 0; + while (*text != '\0' || text[1] != LINE_CMD_EOL) { + args[argcount] = line_read_format(&text); + if (raw != NULL) { + g_string_append_c(raw, '\0'); + g_string_append_c(raw, + (char)LINE_CMD_FORMAT); + + g_string_append(raw, args[argcount]); + } + argcount++; + } + + /* get the format text */ + format_create_dest(&dest, NULL, NULL, line->level, window); + ret = format_get_text_theme_charargs(current_theme, + module, &dest, + formatnum, args); + while (argcount > 0) + g_free(args[--argcount]); + } + + g_free(module); + g_free(format_name); + + return ret; +} + +void gui_window_reformat_line(WINDOW_REC *window, LINE_REC *line) +{ + GUI_WINDOW_REC *gui; + TEXT_DEST_REC dest; + GString *raw; + char *str, *tmp, *prestr, *linestart, *leveltag; + + gui = WINDOW_GUI(window); + + raw = g_string_new(NULL); + str = gui_window_line_get_format(window, line, raw); + + if (str == NULL) { + if (raw->len == 2 && + raw->str[1] == (char)LINE_CMD_FORMAT_CONT) { + /* multiline format, format explained in one the + following lines. remove this line. */ + gui_window_line_remove(window, line); + } + } else { + /* FIXME: ugly ugly .. at least timestamps should be + printed by GUI itself.. server tags are also a bit + problematic.. */ + g_string_append_c(raw, '\0'); + g_string_append_c(raw, (char)LINE_CMD_EOL); + + gui->temp_line = line; + gui->temp_line->text = gui->cur_text->buffer+gui->cur_text->pos; + gui->eol_marked = FALSE; + + format_create_dest(&dest, NULL, NULL, line->level, window); + + linestart = format_get_line_start(current_theme, &dest); + leveltag = format_get_level_tag(current_theme, &dest); + + prestr = g_strconcat(linestart == NULL ? "" : linestart, + leveltag, NULL); + g_free_not_null(linestart); + g_free_not_null(leveltag); + + tmp = format_add_linestart(str, prestr); + g_free(str); + g_free(prestr); + + format_send_to_gui(&dest, tmp); + g_free(tmp); + + gui_window_line_append(gui, raw->str, raw->len); + + gui->eol_marked = TRUE; + gui->temp_line = NULL; + } + g_string_free(raw, TRUE); +} + static void read_settings(void) { default_indent_pos = settings_get_int("indent"); diff --git a/src/fe-text/gui-windows.h b/src/fe-text/gui-windows.h index 1d037722..ec2d8760 100644 --- a/src/fe-text/gui-windows.h +++ b/src/fe-text/gui-windows.h @@ -15,16 +15,16 @@ enum { LINE_CMD_EOL=0x80, /* line ends here. */ LINE_CMD_CONTINUE, /* line continues in next block */ - LINE_CMD_OVERFLOW, /* buffer overflow! */ LINE_CMD_COLOR0, /* change to black, would be same as \0\0 but it breaks things.. */ LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */ LINE_CMD_UNDERLINE, /* enable/disable underlining */ LINE_CMD_INDENT, /* if line is split, indent it at this position */ LINE_CMD_BLINK, /* blinking background */ - LINE_CMD_FORMAT /* end of line, but next will come the format that was used to create the + LINE_CMD_FORMAT, /* end of line, but next will come the format that was used to create the text in format <module><format_name><arg><arg2...> - fields are separated with \0<format> and last argument ends with \0<eol>. \0<continue> is allowed anywhere */ + LINE_CMD_FORMAT_CONT /* multiline format, continues to next line */ }; typedef struct { @@ -56,7 +56,6 @@ typedef struct { typedef struct { char buffer[LINE_TEXT_CHUNK_SIZE]; - char overflow[2]; int pos; int lines; } TEXT_CHUNK_REC; @@ -69,7 +68,7 @@ typedef struct { GList *lines; GHashTable *line_cache; - LINE_REC *cur_line; + LINE_REC *cur_line, *temp_line; TEXT_CHUNK_REC *cur_text; int xpos, ypos; /* cursor position in screen */ @@ -80,7 +79,8 @@ typedef struct { int bottom_subline; int empty_linecount; /* how many empty lines are in screen. a screenful when started or used /CLEAR */ - int bottom; /* window is at the bottom of the text buffer */ + int bottom:1; /* window is at the bottom of the text buffer */ + int eol_marked:1; /* last line marked for eol */ /* For /LAST -new and -away */ GList *lastlog_last_check; @@ -106,6 +106,7 @@ int gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, int ypos, int skip void gui_window_clear(WINDOW_REC *window); void gui_window_redraw(WINDOW_REC *window); +void gui_window_reformat_line(WINDOW_REC *window, LINE_REC *line); void gui_window_resize(WINDOW_REC *window, int ychange, int xchange); void gui_window_reparent(WINDOW_REC *window, MAIN_WINDOW_REC *parent); |