diff options
author | Timo Sirainen <cras@irssi.org> | 2000-05-15 08:25:45 +0000 |
---|---|---|
committer | cras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564> | 2000-05-15 08:25:45 +0000 |
commit | cbdaf7d06d021a1072363f1a80ff73c7423c7bd8 (patch) | |
tree | 067c27c2823ed2825e7fb432b35318659e63e806 /src/fe-text | |
parent | 969cfe8abcdff1047696c22e13c79c1f4c239137 (diff) | |
download | irssi-cbdaf7d06d021a1072363f1a80ff73c7423c7bd8.zip |
Lots of changes again. Biggest ones:
- window's text buffer should work better
- themes are almost working, you can change the text formats with /format
- automatically try to rejoin the channel after 5 minutes if the join there
failed because it was "temporarily unavailable" (netsplits)
- generally cleaning code..
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@216 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/fe-text')
-rw-r--r-- | src/fe-text/gui-printtext.c | 497 | ||||
-rw-r--r-- | src/fe-text/gui-windows.c | 544 | ||||
-rw-r--r-- | src/fe-text/gui-windows.h | 16 | ||||
-rw-r--r-- | src/fe-text/irssi.c | 10 | ||||
-rw-r--r-- | src/fe-text/mainwindows.c | 16 | ||||
-rw-r--r-- | src/fe-text/module-formats.c | 12 | ||||
-rw-r--r-- | src/fe-text/module-formats.h | 3 |
7 files changed, 579 insertions, 519 deletions
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c index 59e00d52..c68b257d 100644 --- a/src/fe-text/gui-printtext.c +++ b/src/fe-text/gui-printtext.c @@ -35,277 +35,272 @@ 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; -static LINE_REC *create_line(GUI_WINDOW_REC *gui, gint level) +#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 = (gint32) GPOINTER_TO_INT(level); - gui->cur_line->time = time(NULL); - - /* temporarily mark the end of line. */ - memcpy(gui->cur_text->buffer+gui->cur_text->pos, "\0\x80", 2); - - gui->last_color = -1; - gui->last_flags = 0; - - gui->lines = g_list_append(gui->lines, gui->cur_line); - if (gui->startline == NULL) - { - gui->startline = gui->lines; - gui->bottom_startline = gui->lines; - } - return gui->cur_line; + 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; - guchar *buffer; - gchar *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) - { - /* mark the next block text block position.. */ - buffer = (guchar *) gui->cur_text->buffer+gui->cur_text->pos; - if (gui->cur_text->pos+2+sizeof(gchar *) > LINE_TEXT_CHUNK_SIZE) - g_error("create_text_chunk() : buffer overflow?!"); - *buffer++ = 0; *buffer++ = LINE_CMD_CONTINUE; - ptr = rec->buffer; - memcpy(buffer, &ptr, sizeof(gchar *)); - } - gui->cur_text = rec; - gui->text_chunks = g_slist_append(gui->text_chunks, rec); - return rec; + 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); + 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); + 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) - { - gui->startline = gui->startline->next; - gui->subline = 0; - } - if (gui->bottom_startline->prev == NULL) - { - 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); + 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 get_colors(gint flags, gint *fg, gint *bg) +static void linebuf_add(GUI_WINDOW_REC *gui, char *str, int len) { - 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) - { - gint 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; + 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 linebuf_add(GUI_WINDOW_REC *gui, gchar *str, gint len) +static void line_add_colors(GUI_WINDOW_REC *gui, int fg, int bg, int flags) { - gint 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 command! */ - 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; + 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 line_add_colors(GUI_WINDOW_REC *gui, gint fg, gint bg, gint flags) +static void gui_printtext(WINDOW_REC *window, gpointer fgcolor, gpointer bgcolor, gpointer pflags, char *str, gpointer level) { - guchar buffer[12]; - gint 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++] = (gchar) 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, (gchar *) buffer, pos); - - gui->last_flags = flags; - gui->last_color = fg | (bg << 4); + GUI_WINDOW_REC *gui; + LINE_REC *line; + int fg, bg, flags, new_lines, n, visible, ypos; + + 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->parent->first_line+gui->ypos-new_lines; + if (new_lines > 0) { + set_color(0); + move(ypos, 0); clrtoeol(); + } + gui_window_line_draw(gui, line, ypos, gui->last_subline, -1); + } + + gui->last_subline += new_lines; } -static void gui_printtext(WINDOW_REC *window, gpointer fgcolor, gpointer bgcolor, gpointer pflags, gchar *str, gpointer level) +static void window_clear(GUI_WINDOW_REC *gui) { - GUI_WINDOW_REC *gui; - LINE_REC *line; - gboolean visible; - gint fg, bg, flags, lines, n; - - 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') - { - linebuf_add(gui, "\0\x80", 2); /* mark EOL */ - line = create_line(gui, 0); - gui_window_newline(gui, visible); - str++; - 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)); - - /* temporarily mark the end of line. */ - memcpy(gui->cur_text->buffer+gui->cur_text->pos, "\0\x80", 2); - - if (visible) - { - /* draw the line to screen. */ - lines = gui_window_line_draw(gui, line, gui->parent->first_line+gui->ypos, gui->last_subline, -1); - } - else - { - /* we still need to update the bottom's position */ - lines = gui_window_get_linecount(gui, line)-1-gui->last_subline; - for (n = 0; n < lines; n++) - gui_window_newline(gui, visible); - } - if (lines > 0) gui->last_subline += lines; + int n; + + for (n = gui->parent->first_line; n <= gui->parent->last_line; n++) { + move(n, 0); + clrtoeol(); + } + screen_refresh(); } -static void cmd_clear(gchar *data) +static void cmd_clear(void) { - GUI_WINDOW_REC *gui; - gint n; - - gui = WINDOW_GUI(active_win); - - if (is_window_visible(active_win)) - { - for (n = gui->parent->first_line; n <= gui->parent->last_line; n++) - { - move(n, 0); - clrtoeol(); - } - screen_refresh(); - } - - 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; + 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) @@ -321,18 +316,18 @@ static void read_settings(void) void gui_printtext_init(void) { - signal_add("gui print text", (SIGNAL_FUNC) gui_printtext); - command_bind("clear", NULL, (SIGNAL_FUNC) cmd_clear); - signal_add("print text finished", (SIGNAL_FUNC) sig_printtext_finished); - signal_add("setup changed", (SIGNAL_FUNC) read_settings); + 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(); + read_settings(); } void gui_printtext_deinit(void) { - signal_remove("gui print text", (SIGNAL_FUNC) gui_printtext); - command_unbind("clear", (SIGNAL_FUNC) cmd_clear); - signal_remove("print text finished", (SIGNAL_FUNC) sig_printtext_finished); - signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + 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); } diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index 60956cce..64d06e98 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -46,6 +46,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *pare gui->parent = parent; gui->bottom = TRUE; + gui->line_cache = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal); gui->line_chunk = g_mem_chunk_new("line chunk", sizeof(LINE_REC), sizeof(LINE_REC)*100, G_ALLOC_AND_FREE); gui->empty_linecount = parent->last_line-parent->first_line; @@ -53,8 +54,19 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *pare return gui; } +int line_cache_destroy(void *key, LINE_CACHE_REC *cache) +{ + g_free_not_null(cache->lines); + g_free(cache); + + return TRUE; +} + static void gui_window_deinit(GUI_WINDOW_REC *gui) { + g_hash_table_foreach(gui->line_cache, (GHFunc) line_cache_destroy, NULL); + g_hash_table_destroy(gui->line_cache); + g_slist_foreach(gui->text_chunks, (GFunc) g_free, NULL); g_slist_free(gui->text_chunks); @@ -106,7 +118,7 @@ static void gui_window_destroyed(WINDOW_REC *window) gui_window_deinit(gui); window->gui_data = NULL; - if (mainwindows->next != NULL && parent->active == window) + if (parent->active == window && mainwindows->next != NULL) mainwindow_destroy(parent); } @@ -126,322 +138,337 @@ void gui_window_clear(WINDOW_REC *window) gui_window_redraw(window); } -int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines) +/* update bottom_startline and bottom_subline of window. */ +static int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines) { - int linecount, last_linecount; - - if (gui->bottom_startline == NULL) - return -1; + int linecount, last_linecount; - while (lines < 0) - { - if (gui->bottom_subline > 0) - gui->bottom_subline--; - else - { - if (gui->bottom_startline->prev == NULL) + if (gui->bottom_startline == NULL) return -1; - gui->bottom_startline = gui->bottom_startline->prev; - linecount = gui_window_get_linecount(gui, gui->bottom_startline->data); - gui->bottom_subline = linecount-1; - } - lines++; - } + for (; lines < 0; lines++) { + if (gui->bottom_subline > 0) { + gui->bottom_subline--; + continue; + } - last_linecount = linecount = -1; - while (lines > 0) - { - if (linecount == -1) - last_linecount = linecount = gui_window_get_linecount(gui, gui->bottom_startline->data); + if (gui->bottom_startline->prev == NULL) + return -1; + gui->bottom_startline = gui->bottom_startline->prev; - if (linecount > gui->bottom_subline+1) - gui->bottom_subline++; - else - { - gui->bottom_subline = 0; - linecount = -1; + linecount = gui_window_get_linecount(gui, gui->bottom_startline->data); + gui->bottom_subline = linecount-1; + } + + last_linecount = -1; + for (; lines > 0; lines--) { + last_linecount = linecount = + gui_window_get_linecount(gui, gui->bottom_startline->data); - if (gui->bottom_startline->next == NULL) - break; - gui->bottom_startline = gui->bottom_startline->next; + if (linecount > gui->bottom_subline+1) + gui->bottom_subline++; + else { + gui->bottom_subline = 0; + if (gui->bottom_startline->next == NULL) + break; + gui->bottom_startline = gui->bottom_startline->next; + } + lines--; } - lines--; - } - return last_linecount; + return last_linecount; } -void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible) +void gui_window_newline(GUI_WINDOW_REC *gui, int visible) { - gboolean last_line; - gint linecount; + int lines; - g_return_if_fail(gui != NULL); + g_return_if_fail(gui != NULL); - gui->xpos = 0; - last_line = gui->ypos >= gui->parent->last_line-gui->parent->first_line; + gui->xpos = 0; - if (gui->empty_linecount > 0) - { - /* window buffer height isn't even the size of the screen yet */ - gui->empty_linecount--; - linecount = gui_window_get_linecount(gui, gui->startline->data); - } - else - { - linecount = gui_window_update_bottom(gui, 1); - } + if (gui->empty_linecount > 0) { + /* window buffer height isn't even the size of the screen yet */ + gui->empty_linecount--; + gui->ypos++; + return; + } - if (!last_line || !gui->bottom) - { - gui->ypos++; - } - else if (gui->bottom) - { - if (gui->subline >= linecount) - { - /* after screen gets full after /CLEAR we end up here.. */ - gui->startline = gui->startline->next; - gui->subline = 0; + lines = gui_window_update_bottom(gui, 1); - linecount = gui_window_update_bottom(gui, 1); + if (!gui->bottom) { + gui->ypos++; + return; } - if (linecount > 1+gui->subline) - gui->subline++; - else - { - gui->startline = gui->startline->next; - gui->subline = 0; + if (gui->subline >= lines) { + /* after screen gets full after /CLEAR we end up here.. */ + gui->startline = gui->startline->next; + gui->subline = 0; + + lines = gui_window_update_bottom(gui, 1); } - if (visible) - { - scroll_up(gui->parent->first_line, gui->parent->last_line); - move(gui->parent->last_line, 0); clrtoeol(); + if (lines > 1+gui->subline) + gui->subline++; + else { + gui->startline = gui->startline->next; + gui->subline = 0; + } + + if (visible) { + scroll_up(gui->parent->first_line, gui->parent->last_line); + move(gui->parent->last_line, 0); clrtoeol(); } - } } -/* get number of real lines that line record takes - this really should share - at least some code with gui_window_line_draw().. */ -gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line) +static LINE_CACHE_REC *gui_window_line_cache(GUI_WINDOW_REC *gui, LINE_REC *line) { - gchar *ptr, *last_space_ptr, *tmp; - gint lines, xpos, indent_pos, last_space; + LINE_CACHE_REC *rec; + LINE_CACHE_SUB_REC *sub; + GSList *lines; + unsigned char *ptr, *last_space_ptr; + int xpos, pos, indent_pos, last_space, color; + + g_return_val_if_fail(line->text != NULL, NULL); + + rec = g_new(LINE_CACHE_REC, 1); + + xpos = 0; color = 0; indent_pos = DEFAULT_INDENT_POS; + last_space = 0; last_space_ptr = NULL; + + rec->count = 1; lines = NULL; + for (ptr = (unsigned char *) line->text;;) { + if (*ptr == '\0') { + /* command */ + ptr++; + if (*ptr == LINE_CMD_EOL) + break; + + if (*ptr == LINE_CMD_CONTINUE) { + char *tmp; + + memcpy(&tmp, ptr+1, sizeof(char *)); + ptr = tmp; + continue; + } + + if ((*ptr & 0x80) == 0) { + /* set color */ + color = (color & ATTR_UNDERLINE) | *ptr; + } else switch (*ptr) { + case LINE_CMD_OVERFLOW: + g_error("buffer overflow!"); + case LINE_CMD_UNDERLINE: + color ^= ATTR_UNDERLINE; + break; + case LINE_CMD_COLOR8: + color &= 0xfff0; + color |= 8|ATTR_COLOR8; + break; + case LINE_CMD_INDENT: + /* set indentation position here - don't do + it if we're too close to right border */ + if (xpos < COLS-5) indent_pos = xpos; + break; + } + + ptr++; + continue; + } - g_return_val_if_fail(gui != NULL, -1); - g_return_val_if_fail(line != NULL, -1); + if (xpos == COLS) { + xpos = indent_pos; - if (line->text == NULL) - return 0; + if (last_space > indent_pos && last_space > 10) { + /* go back to last space */ + ptr = last_space_ptr; + while (*ptr == ' ') ptr++; + } - xpos = 0; lines = 1; indent_pos = DEFAULT_INDENT_POS; - last_space = 0; last_space_ptr = NULL; - for (ptr = line->text;; ptr++) - { - if (*ptr == '\0') - { - /* command */ - ptr++; - switch ((guchar) *ptr) - { - case LINE_CMD_OVERFLOW: - g_error("buffer overflow!"); - case LINE_CMD_EOL: - return lines; - case LINE_CMD_CONTINUE: - memcpy(&tmp, ptr+1, sizeof(gchar *)); - ptr = tmp-1; - break; - case LINE_CMD_INDENT: - indent_pos = xpos; - break; - } - continue; - } + sub = g_new(LINE_CACHE_SUB_REC, 1); + sub->start = ptr; + sub->indent = indent_pos; + sub->color = color; - if (xpos == COLS) - { - xpos = indent_pos >= COLS-5 ? DEFAULT_INDENT_POS : indent_pos; + lines = g_slist_append(lines, sub); + rec->count++; - if (last_space > indent_pos && last_space > 10) - { - ptr = last_space_ptr; - while (*ptr == ' ') ptr++; - } + last_space = 0; + continue; + } - last_space = 0; - lines++; - ptr--; - continue; + xpos++; + if (*ptr++ == ' ') { + last_space = xpos-1; + last_space_ptr = ptr; + } } - xpos++; - if (*ptr == ' ') - { - last_space = xpos-1; - last_space_ptr = ptr+1; + if (rec->count < 2) + rec->lines = NULL; + else { + rec->lines = g_new(LINE_CACHE_SUB_REC, rec->count-1); + for (pos = 0; lines != NULL; pos++) { + memcpy(&rec->lines[pos], lines->data, sizeof(LINE_CACHE_SUB_REC)); + + g_free(lines->data); + lines = g_slist_remove(lines, lines->data); + } } - } + + g_hash_table_insert(gui->line_cache, line, rec); + return rec; } -/* draw line - ugly code.. */ -gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint skip, gint max) +void gui_window_cache_remove(GUI_WINDOW_REC *gui, LINE_REC *line) { - gchar *ptr, *last_space_ptr, *tmp; - gint lines, xpos, color, indent_pos, last_space, last_space_color; + LINE_CACHE_REC *cache; - g_return_val_if_fail(gui != NULL, -1); - g_return_val_if_fail(line != NULL, -1); + g_return_if_fail(gui != NULL); + g_return_if_fail(line != NULL); - if (line->text == NULL) - return 0; - - move(ypos, 0); - xpos = 0; color = 0; lines = -1; indent_pos = DEFAULT_INDENT_POS; - last_space = last_space_color = 0; last_space_ptr = NULL; - for (ptr = line->text;; ptr++) - { - if (*ptr == '\0') - { - /* command */ - ptr++; - if ((*ptr & 0x80) == 0) - { - /* set color */ - color = (color & ATTR_UNDERLINE) | *ptr; - } - else switch ((guchar) *ptr) - { - case LINE_CMD_OVERFLOW: - g_error("buffer overflow!"); - case LINE_CMD_EOL: - return lines; - case LINE_CMD_CONTINUE: - memcpy(&tmp, ptr+1, sizeof(gchar *)); - ptr = tmp-1; - break; - case LINE_CMD_UNDERLINE: - color ^= ATTR_UNDERLINE; - break; - case LINE_CMD_COLOR8: - color &= 0xfff0; - color |= 8|ATTR_COLOR8; - break; - case LINE_CMD_BEEP: - beep(); - break; - case LINE_CMD_INDENT: - indent_pos = xpos; - break; - } - set_color(color); - continue; + cache = g_hash_table_lookup(gui->line_cache, line); + if (cache != NULL) { + g_hash_table_remove(gui->line_cache, line); + g_free_not_null(cache->lines); + g_free(cache); } +} - if (xpos == COLS) - { - xpos = indent_pos >= COLS-5 ? DEFAULT_INDENT_POS : indent_pos; +int gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line) +{ + LINE_CACHE_REC *cache; - if (last_space > indent_pos && last_space > 10) - { - /* remove the last word */ - if (!skip) - { - move(ypos, last_space); - set_color(0); - clrtoeol(); - } + g_return_val_if_fail(gui != NULL, -1); + g_return_val_if_fail(line != NULL, -1); - /* skip backwards to draw the line again. */ - ptr = last_space_ptr; - color = last_space_color; - if (!skip) set_color(color); - while (*ptr == ' ') ptr++; - } - last_space = 0; + cache = g_hash_table_lookup(gui->line_cache, line); + if (cache == NULL) + cache = gui_window_line_cache(gui, line); - if (skip > 0) - { - if (--skip == 0) set_color(color); - } - else - { - if (lines == max) - return lines; - if (max != -1) - ypos++; - else - { - gui_window_newline(gui, TRUE); - ypos = gui->parent->first_line+gui->ypos; - } - lines++; - } - move(ypos, indent_pos); + return cache->count; +} - /* we could have \0.. */ - ptr--; - continue; - } +static void single_line_draw(GUI_WINDOW_REC *gui, int ypos, LINE_CACHE_SUB_REC *rec, const char *text, const char *text_end) +{ + char *tmp; + int xpos, color; - xpos++; - if (*ptr == ' ') - { - last_space = xpos-1; - last_space_color = color; - last_space_ptr = ptr+1; + if (rec == NULL) { + xpos = 0; color = 0; + } else { + xpos = rec->indent; + color = rec->color; } - if (skip) continue; - if (lines == -1) lines = 0; + move(ypos, xpos); + while (text != text_end) { + if (*text == '\0') { + /* command */ + text++; + if ((*text & 0x80) == 0) { + /* set color */ + color = (color & ATTR_UNDERLINE) | *text; + } else if (*text == (char) LINE_CMD_CONTINUE) { + /* jump to next block */ + memcpy(&tmp, text+1, sizeof(char *)); + text = tmp; + continue; + } else switch ((unsigned char) *text) { + case LINE_CMD_OVERFLOW: + g_error("buffer overflow!"); + case LINE_CMD_EOL: + return; + case LINE_CMD_UNDERLINE: + color ^= ATTR_UNDERLINE; + break; + case LINE_CMD_COLOR8: + color &= 0xfff0; + color |= 8|ATTR_COLOR8; + break; + } + set_color(color); + text++; + continue; + } - if ((guchar) *ptr >= 32) - addch((guchar) *ptr); - else - { - /* low-ascii */ - set_color(ATTR_REVERSE); - addch(*ptr+'A'-1); - set_color(color); + if (xpos == COLS) { + /* there should be only spaces left */ + text++; + continue; + } + + if ((unsigned char) *text >= 32) + addch((unsigned char) *text); + else { + /* low-ascii */ + set_color(ATTR_REVERSE); + addch(*text+'A'-1); + set_color(color); + } + text++; } - } +} + +int gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, int ypos, int skip, int max) +{ + LINE_CACHE_REC *cache; + LINE_CACHE_SUB_REC *sub; + char *pos, *next_pos; + int n; + + g_return_val_if_fail(gui != NULL, -1); + g_return_val_if_fail(line != NULL, -1); + + cache = g_hash_table_lookup(gui->line_cache, line); + if (cache == NULL) + cache = gui_window_line_cache(gui, line); + + if (max < 0) max = cache->count; + + for (n = skip; n < cache->count && max > 0; n++, ypos++, max--) { + sub = n == 0 ? NULL : &cache->lines[n-1]; + pos = sub == NULL ? line->text : sub->start; + next_pos = (n+1 < cache->count) ? + cache->lines[n].start : NULL; + single_line_draw(gui, ypos, sub, pos, next_pos); + } + + return cache->count; } void gui_window_redraw(WINDOW_REC *window) { - GUI_WINDOW_REC *gui; - GList *line; - gint ypos, lines, skip, max; + GUI_WINDOW_REC *gui; + GList *line; + int ypos, lines, skip, max; - g_return_if_fail(window != NULL); + g_return_if_fail(window != NULL); - gui = WINDOW_GUI(window); + gui = WINDOW_GUI(window); - for (ypos = gui->parent->first_line; ypos <= gui->parent->last_line; ypos++) - { + /* clear the lines first */ set_color(0); - move(ypos, 0); - clrtoeol(); - } + for (ypos = gui->parent->first_line; ypos <= gui->parent->last_line; ypos++) { + move(ypos, 0); + clrtoeol(); + } - skip = gui->subline; - ypos = gui->parent->first_line; - for (line = gui->startline; line != NULL; line = line->next) - { - LINE_REC *rec = line->data; + skip = gui->subline; + ypos = gui->parent->first_line; + for (line = gui->startline; line != NULL; line = line->next) { + LINE_REC *rec = line->data; - max = gui->parent->last_line - ypos; - if (max < 0) break; + max = gui->parent->last_line - ypos+1; + if (max < 0) break; - lines = gui_window_line_draw(gui, rec, ypos, skip, max); - skip = 0; + lines = gui_window_line_draw(gui, rec, ypos, skip, max); + ypos += lines-skip; + skip = 0; + } - ypos += lines+1; - } - screen_refresh(); + screen_refresh(); } static void gui_window_scroll_up(GUI_WINDOW_REC *gui, gint lines) @@ -579,6 +606,8 @@ static void signal_window_changed(WINDOW_REC *window) { g_return_if_fail(window != NULL); + if (quitting) return; + if (is_window_visible(window)) { /* already visible, great! */ active_mainwin = WINDOW_GUI(window)->parent; @@ -674,6 +703,8 @@ static void gui_window_horiz_resize(WINDOW_REC *window) gui = WINDOW_GUI(window); if (gui->lines == NULL) return; + g_hash_table_foreach_remove(gui->line_cache, (GHRFunc) line_cache_destroy, NULL); + linecount = gui_window_get_linecount(gui, g_list_last(gui->lines)->data); gui->last_subline = linecount-1; @@ -703,7 +734,8 @@ void gui_window_resize(WINDOW_REC *window, int ychange, int xchange) gui = WINDOW_GUI(window); if (xchange) { - /* window width changed, we'll need to recalculate a few things.. */ + /* window width changed, we'll need to recalculate a + few things.. */ gui_window_horiz_resize(window); return; } diff --git a/src/fe-text/gui-windows.h b/src/fe-text/gui-windows.h index 28dde1e9..622b5f4a 100644 --- a/src/fe-text/gui-windows.h +++ b/src/fe-text/gui-windows.h @@ -23,6 +23,17 @@ enum { }; typedef struct { + char *start; + int indent; + int color; +} LINE_CACHE_SUB_REC; + +typedef struct { + int count; /* number of real lines */ + LINE_CACHE_SUB_REC *lines; +} LINE_CACHE_REC; + +typedef struct { /* text in the line. \0 means that the next char will be a color or command. <= 127 = color or if 8.bit is set, the first 7 bits are the command. See LINE_CMD_xxxx. */ @@ -45,6 +56,7 @@ typedef struct { GMemChunk *line_chunk; GSList *text_chunks; GList *lines; + GHashTable *line_cache; LINE_REC *cur_line; TEXT_CHUNK_REC *cur_text; @@ -74,6 +86,7 @@ GList *gui_window_find_text(WINDOW_REC *window, char *text, GList *startline, in /* get number of real lines that line record takes */ int gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line); +void gui_window_cache_remove(GUI_WINDOW_REC *gui, LINE_REC *line); int gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, int ypos, int skip, int max); void gui_window_clear(WINDOW_REC *window); @@ -82,8 +95,7 @@ void gui_window_resize(WINDOW_REC *window, int ychange, int xchange); void gui_window_reparent(WINDOW_REC *window, MAIN_WINDOW_REC *parent); void window_update_prompt(WINDOW_REC *window); -void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible); -int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines); +void gui_window_newline(GUI_WINDOW_REC *gui, int visible); void gui_window_scroll(WINDOW_REC *window, int lines); #endif diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index 2c95b87d..ee8e3bf5 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -19,6 +19,7 @@ */ #include "module.h" +#include "module-formats.h" #include "args.h" #include "signals.h" #include "core.h" @@ -26,6 +27,7 @@ #include "irc-core.h" #include "fe-common-core.h" #include "fe-common-irc.h" +#include "themes.h" #include "screen.h" #include "gui-entry.h" @@ -82,6 +84,8 @@ static void textui_init(void) irc_init(); fe_common_core_init(); fe_common_irc_init(); + + theme_register(gui_text_formats); signal_add("gui exit", (SIGNAL_FUNC) sig_exit); } @@ -91,11 +95,11 @@ static void textui_finish_init(void) screen_refresh_freeze(); gui_entry_init(); - mainwindows_init(); gui_printtext_init(); gui_readline_init(); gui_special_vars_init(); gui_textwidget_init(); + mainwindows_init(); gui_windows_init(); statusbar_init(); @@ -123,11 +127,13 @@ static void textui_deinit(void) statusbar_deinit(); gui_printtext_deinit(); gui_readline_deinit(); - mainwindows_deinit(); gui_windows_deinit(); + mainwindows_deinit(); gui_entry_deinit(); deinit_screen(); + theme_unregister(); + fe_common_irc_deinit(); fe_common_core_deinit(); irc_deinit(); diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c index 35bf4ecd..e30c0eb4 100644 --- a/src/fe-text/mainwindows.c +++ b/src/fe-text/mainwindows.c @@ -347,6 +347,17 @@ static void mainwindows_resize_bigger(int ychange, int xchange) g_slist_free(sorted); } +void mainwindows_resize_horiz(int xchange) +{ + GSList *tmp; + + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + mainwindow_resize(rec, 0, xchange); + } +} + void mainwindows_resize(int ychange, int xchange) { screen_refresh_freeze(); @@ -354,6 +365,8 @@ void mainwindows_resize(int ychange, int xchange) mainwindows_resize_smaller(ychange, xchange); else if (ychange > 0) mainwindows_resize_bigger(ychange, xchange); + else if (xchange != 0) + mainwindows_resize_horiz(xchange); irssi_redraw(); screen_refresh_thaw(); @@ -595,6 +608,9 @@ void mainwindows_init(void) void mainwindows_deinit(void) { + while (mainwindows != NULL) + mainwindow_destroy(mainwindows->data); + command_unbind("window grow", (SIGNAL_FUNC) cmd_window_grow); command_unbind("window shrink", (SIGNAL_FUNC) cmd_window_shrink); command_unbind("window size", (SIGNAL_FUNC) cmd_window_size); diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c index 9b38fecb..f81088df 100644 --- a/src/fe-text/module-formats.c +++ b/src/fe-text/module-formats.c @@ -23,11 +23,13 @@ FORMAT_REC gui_text_formats[] = { - { MODULE_NAME, "Text user interface", 0 }, + { MODULE_NAME, "Text user interface", 0 }, - { "lastlog_start", "%_Lastlog:", 0 }, - { "lastlog_end", "%_End of Lastlog", 0 }, + { "lastlog_start", "%_Lastlog:", 0 }, + { "lastlog_end", "%_End of Lastlog", 0 }, - { "window_too_small", "Not enough room to resize this window", 0 }, - { "cant_hide_last", "You can't hide the last window", 0 } + { "window_too_small", "Not enough room to resize this window", 0 }, + { "cant_hide_last", "You can't hide the last window", 0 }, + + { NULL, NULL, 0 } }; diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h index 39d29182..2af040eb 100644 --- a/src/fe-text/module-formats.h +++ b/src/fe-text/module-formats.h @@ -11,6 +11,3 @@ enum { }; extern FORMAT_REC gui_text_formats[]; -#define MODULE_FORMATS gui_text_formats - -#include "printformat.h" |