From fb439b5c2ae93e0d42a59cf8900a17cbb72214f6 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 28 Oct 2001 18:40:12 +0000 Subject: [PATCH] Redrawing fixes - irssi should now rarely redraw stuff uselessly in screen. Most of the code now just marks the window/statusbar/etc. as dirty, and lets the dirty-checker handle it later. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@1926 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/fe-text/gui-entry.c | 35 +++++++- src/fe-text/gui-entry.h | 4 +- src/fe-text/gui-windows.c | 14 +++- src/fe-text/irssi.c | 50 ++++++++++-- src/fe-text/mainwindows.c | 57 ++++++------- src/fe-text/mainwindows.h | 7 +- src/fe-text/module.h | 1 + src/fe-text/statusbar-config.c | 2 +- src/fe-text/statusbar-items.c | 20 ++--- src/fe-text/statusbar.c | 142 +++++++++++++++++++++++++-------- src/fe-text/statusbar.h | 10 ++- src/fe-text/term-terminfo.c | 38 +++++++-- src/fe-text/terminfo-core.c | 43 +++++++++- src/fe-text/terminfo-core.h | 6 +- src/fe-text/textbuffer-view.c | 40 ++++++---- src/fe-text/textbuffer-view.h | 2 + 16 files changed, 348 insertions(+), 123 deletions(-) diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c index f3f2463e..77cd0f02 100644 --- a/src/fe-text/gui-entry.c +++ b/src/fe-text/gui-entry.c @@ -54,6 +54,9 @@ void gui_entry_destroy(GUI_ENTRY_REC *entry) /* Fixes the cursor position in screen */ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry) { + int old_scrstart; + + old_scrstart = entry->scrstart; if (entry->pos - entry->scrstart < entry->width-2 - entry->promptlen && entry->pos - entry->scrstart > 0) { entry->scrpos = entry->pos - entry->scrstart; @@ -64,6 +67,9 @@ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry) entry->scrpos = (entry->width - entry->promptlen)*2/3; entry->scrstart = entry->pos - entry->scrpos; } + + if (old_scrstart != entry->scrstart) + entry->redraw_needed_from = 0; } static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos) @@ -102,15 +108,28 @@ static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos) xpos++; } } +} + +static void gui_entry_draw(GUI_ENTRY_REC *entry) +{ + if (entry->redraw_needed_from >= 0) { + gui_entry_draw_from(entry, entry->redraw_needed_from); + entry->redraw_needed_from = -1; + } term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen, entry->ypos); term_refresh(NULL); } -static void gui_entry_draw(GUI_ENTRY_REC *entry) +static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos) { - gui_entry_draw_from(entry, 0); + pos -= entry->scrstart; + if (pos < 0) pos = 0; + + if (entry->redraw_needed_from == -1 || + entry->redraw_needed_from > pos) + entry->redraw_needed_from = pos; } void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width) @@ -135,7 +154,7 @@ void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width) /* input line grew - need to draw text at the end */ old_width = width; entry->width = width; - gui_entry_draw_from(entry, old_width); + gui_entry_redraw_from(entry, old_width); } else { /* input line shrinked - make sure the cursor is inside the input line */ @@ -143,9 +162,10 @@ void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width) if (entry->pos - entry->scrstart > entry->width-2 - entry->promptlen) { gui_entry_fix_cursor(entry); - gui_entry_draw(entry); } } + + gui_entry_draw(entry); } void gui_entry_set_active(GUI_ENTRY_REC *entry) @@ -196,6 +216,7 @@ void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str) g_string_assign(entry->text, str); entry->pos = entry->text->len; + gui_entry_redraw_from(entry, 0); gui_entry_fix_cursor(entry); gui_entry_draw(entry); } @@ -212,6 +233,7 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str) g_return_if_fail(entry != NULL); g_return_if_fail(str != NULL); + gui_entry_redraw_from(entry, entry->pos); g_string_insert(entry->text, entry->pos, str); entry->pos += strlen(str); @@ -226,6 +248,7 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, char chr) if (chr == 0) return; /* never insert NUL characters */ + gui_entry_redraw_from(entry, entry->pos); g_string_insert_c(entry->text, entry->pos, chr); entry->pos++; @@ -249,6 +272,7 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size) entry->pos -= size; g_string_erase(entry->text, entry->pos, size); + gui_entry_redraw_from(entry, entry->pos); gui_entry_fix_cursor(entry); gui_entry_draw(entry); } @@ -279,6 +303,7 @@ void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space) g_string_erase(entry->text, to, entry->pos - to); entry->pos = to; + gui_entry_redraw_from(entry, entry->pos); gui_entry_fix_cursor(entry); gui_entry_draw(entry); } @@ -306,6 +331,7 @@ void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space) g_string_erase(entry->text, entry->pos, to - entry->pos); + gui_entry_redraw_from(entry, entry->pos); gui_entry_fix_cursor(entry); gui_entry_draw(entry); } @@ -412,6 +438,7 @@ void gui_entry_redraw(GUI_ENTRY_REC *entry) g_return_if_fail(entry != NULL); gui_entry_set_prompt(entry, NULL); + gui_entry_redraw_from(entry, 0); gui_entry_fix_cursor(entry); gui_entry_draw(entry); } diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h index 0c2b4a4b..70bccb55 100644 --- a/src/fe-text/gui-entry.h +++ b/src/fe-text/gui-entry.h @@ -8,7 +8,9 @@ typedef struct { int hidden; /* print the chars as spaces in input line (useful for passwords) */ int promptlen; - char *prompt; + char *prompt; + + int redraw_needed_from; } GUI_ENTRY_REC; extern GUI_ENTRY_REC *active_entry; diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index 5c6f00e5..1ce50fb6 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -117,8 +117,14 @@ void gui_window_resize(WINDOW_REC *window, int width, int height) { GUI_WINDOW_REC *gui; + if (window->width == width && window->height == height) + return; + gui = WINDOW_GUI(window); + irssi_set_dirty(); + WINDOW_MAIN(window)->dirty = TRUE; + window->width = width; window->height = height; textbuffer_view_resize(gui->view, width, height); @@ -248,14 +254,16 @@ static void signal_window_changed(WINDOW_REC *window) gui_window_reparent(window, active_mainwin); } - old_window = active_mainwin->active; - if (old_window != NULL) - textbuffer_view_set_window(WINDOW_GUI(old_window)->view, NULL); + old_window = active_mainwin->active; + if (old_window != NULL && old_window != window) + textbuffer_view_set_window(WINDOW_GUI(old_window)->view, NULL); active_mainwin->active = window; textbuffer_view_set_window(WINDOW_GUI(window)->view, parent->screen_win); + if (WINDOW_GUI(window)->view->dirty) + active_mainwin->dirty = TRUE; } static void read_settings(void) diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index e625e595..863adfd3 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -69,6 +69,8 @@ void mainwindow_activity_deinit(void); void mainwindows_layout_init(void); void mainwindows_layout_deinit(void); +static int dirty, full_redraw; + static GMainLoop *main_loop; int quitting; @@ -85,19 +87,43 @@ static int display_firsttimer = FALSE; static void sig_exit(void) { - g_main_quit(main_loop); + quitting = TRUE; } /* redraw irssi's screen.. */ void irssi_redraw(void) { - term_clear(); + dirty = TRUE; + full_redraw = TRUE; +} + +void irssi_set_dirty(void) +{ + dirty = TRUE; +} + +static void dirty_check(void) +{ + if (!dirty) + return; + + if (full_redraw) { + full_redraw = FALSE; + + /* first clear the screen so curses will be + forced to redraw the screen */ + term_clear(); + term_refresh(NULL); + + mainwindows_redraw(); + statusbar_redraw(NULL, TRUE); + } + + mainwindows_redraw_dirty(); + statusbar_redraw_dirty(); term_refresh(NULL); - /* windows */ - mainwindows_redraw(); - /* statusbar */ - statusbar_redraw(NULL); + dirty = FALSE; } static void textui_init(void) @@ -152,7 +178,6 @@ static void textui_finish_init(void) static void textui_deinit(void) { - quitting = TRUE; signal(SIGINT, SIG_DFL); term_refresh_freeze(); @@ -164,6 +189,7 @@ static void textui_deinit(void) fe_perl_deinit(); #endif + dirty_check(); /* one last time to print any quit messages */ signal_remove("gui exit", (SIGNAL_FUNC) sig_exit); lastlog_deinit(); @@ -256,6 +282,7 @@ static void winsock_init(void) int main(int argc, char **argv) { + quitting = FALSE; core_init_paths(argc, argv); check_files(); @@ -279,7 +306,14 @@ int main(int argc, char **argv) textui_finish_init(); main_loop = g_main_new(TRUE); - g_main_run(main_loop); + + /* Does the same as g_main_run(main_loop), except we + can call our dirty-checker after each iteration */ + while (!quitting) { + g_main_iteration(TRUE); + dirty_check(); + } + g_main_destroy(main_loop); textui_deinit(); diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c index 0d1c3f19..c849f6cd 100644 --- a/src/fe-text/mainwindows.c +++ b/src/fe-text/mainwindows.c @@ -75,10 +75,9 @@ static void mainwindow_resize_windows(MAIN_WINDOW_REC *window) { GSList *tmp; - if (window->resize_freeze_counter > 0) { - window->resize_needed = TRUE; - return; - } + if (window->active->width == window->width && + window->active->height == MAIN_WINDOW_TEXT_HEIGHT(window)) + return; mainwindow_set_screen_size(window); for (tmp = windows; tmp != NULL; tmp = tmp->next) { @@ -101,7 +100,7 @@ static void mainwindow_resize(MAIN_WINDOW_REC *window, int xdiff, int ydiff) window->width += xdiff; window->height = window->last_line-window->first_line+1; - mainwindow_resize_windows(window); + window->size_dirty = TRUE; } static GSList *get_sticky_windows_sorted(MAIN_WINDOW_REC *mainwin) @@ -165,6 +164,7 @@ void mainwindows_recreate(void) MAIN_WINDOW_REC *rec = tmp->data; rec->screen_win = mainwindow_create_screen(rec); + rec->dirty = TRUE; textbuffer_view_set_window(WINDOW_GUI(rec->active)->view, rec->screen_win); } @@ -308,13 +308,12 @@ void mainwindows_redraw(void) { GSList *tmp; - term_refresh_freeze(); + irssi_set_dirty(); for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { MAIN_WINDOW_REC *rec = tmp->data; - gui_window_redraw(rec->active); + rec->dirty = TRUE; } - term_refresh_thaw(); } static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2) @@ -453,7 +452,6 @@ void mainwindows_resize(int width, int height) old_screen_width = width; old_screen_height = height; - term_refresh_freeze(); if (ydiff < 0) mainwindows_resize_smaller(xdiff, ydiff); else if (ydiff > 0) @@ -462,7 +460,6 @@ void mainwindows_resize(int width, int height) mainwindows_resize_horiz(xdiff); signal_emit("terminal resized", 0); - term_refresh_thaw(); irssi_redraw(); } @@ -521,32 +518,20 @@ int mainwindow_set_statusbar_lines(MAIN_WINDOW_REC *window, } if (top+bottom != 0) - mainwindow_resize_windows(window); + window->size_dirty = TRUE; return ret; } -void mainwindow_resize_freeze(MAIN_WINDOW_REC *window) -{ - window->resize_freeze_counter++; -} - -void mainwindow_resize_thaw(MAIN_WINDOW_REC *window) -{ - if (--window->resize_freeze_counter == 0 && - window->resize_needed) { - window->resize_needed = FALSE; - mainwindow_resize_windows(window); - } -} - static void mainwindows_resize_two(MAIN_WINDOW_REC *grow_win, MAIN_WINDOW_REC *shrink_win, int count) { + irssi_set_dirty(); + mainwindow_resize(grow_win, 0, count); mainwindow_resize(shrink_win, 0, -count); - gui_window_redraw(grow_win->active); - gui_window_redraw(shrink_win->active); + grow_win->dirty = TRUE; + shrink_win->dirty = TRUE; } static int try_shrink_lower(MAIN_WINDOW_REC *window, int count) @@ -649,6 +634,24 @@ void mainwindow_set_size(MAIN_WINDOW_REC *window, int height, int resize_lower) mainwindow_grow(window, height, resize_lower); } +void mainwindows_redraw_dirty(void) +{ + GSList *tmp; + + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->size_dirty) { + rec->size_dirty = FALSE; + mainwindow_resize_windows(rec); + } + if (rec->dirty) { + rec->dirty = FALSE; + gui_window_redraw(rec->active); + } + } +} + /* SYNTAX: WINDOW GROW [] */ static void cmd_window_grow(const char *data) { diff --git a/src/fe-text/mainwindows.h b/src/fe-text/mainwindows.h index 6306758f..1bca333d 100644 --- a/src/fe-text/mainwindows.h +++ b/src/fe-text/mainwindows.h @@ -23,8 +23,8 @@ typedef struct { int statusbar_lines_bottom; int statusbar_lines; /* top+bottom */ - int resize_freeze_counter; - unsigned int resize_needed:1; /* We'll need to resize the window, but haven't got around doing it just yet. */ + unsigned int dirty:1; /* This window needs a redraw */ + unsigned int size_dirty:1; /* We'll need to resize the window, but haven't got around doing it just yet. */ } MAIN_WINDOW_REC; extern GSList *mainwindows; @@ -53,8 +53,7 @@ void mainwindow_change_active(MAIN_WINDOW_REC *mainwin, int mainwindows_reserve_lines(int top, int bottom); int mainwindow_set_statusbar_lines(MAIN_WINDOW_REC *window, int top, int bottom); -void mainwindow_resize_freeze(MAIN_WINDOW_REC *window); -void mainwindow_resize_thaw(MAIN_WINDOW_REC *window); +void mainwindows_redraw_dirty(void); GSList *mainwindows_get_sorted(int reverse); diff --git a/src/fe-text/module.h b/src/fe-text/module.h index ba5888ad..c6643545 100644 --- a/src/fe-text/module.h +++ b/src/fe-text/module.h @@ -4,3 +4,4 @@ extern int quitting; void irssi_redraw(void); +void irssi_set_dirty(void); diff --git a/src/fe-text/statusbar-config.c b/src/fe-text/statusbar-config.c index f703afa7..390ce193 100644 --- a/src/fe-text/statusbar-config.c +++ b/src/fe-text/statusbar-config.c @@ -218,7 +218,7 @@ static void create_root_statusbars(void) if (rec->type == STATUSBAR_TYPE_ROOT) { bar = statusbar_create(active_statusbar_group, rec, NULL); - statusbar_redraw(bar); + statusbar_redraw(bar, TRUE); } } } diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c index 70547daf..da485d5b 100644 --- a/src/fe-text/statusbar-items.c +++ b/src/fe-text/statusbar-items.c @@ -276,23 +276,23 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only) { GUI_ENTRY_REC *rec; - if (get_size_only) { - item->min_size = 2+term_width/10; - item->max_size = term_width; - return; - } - rec = g_hash_table_lookup(input_entries, item); if (rec == NULL) { rec = gui_entry_create(item->xpos, item->bar->real_ypos, item->size); gui_entry_set_active(rec); g_hash_table_insert(input_entries, item, rec); - } else { - gui_entry_move(rec, item->xpos, item->bar->real_ypos, - item->size); - gui_entry_redraw(rec); /* FIXME: this is only necessary with ^L.. */ } + + if (get_size_only) { + item->min_size = 2+term_width/10; + item->max_size = term_width; + return; + } + + gui_entry_move(rec, item->xpos, item->bar->real_ypos, + item->size); + gui_entry_redraw(rec); /* FIXME: this is only necessary with ^L.. */ } static void sig_statusbar_item_destroyed(SBAR_ITEM_REC *item) diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c index 0ed75fed..5ca83f70 100644 --- a/src/fe-text/statusbar.c +++ b/src/fe-text/statusbar.c @@ -225,7 +225,12 @@ static void statusbar_resize_items(STATUSBAR_REC *bar, int max_width) g_slist_free(prior_sorted); } -static void statusbar_redraw_items(STATUSBAR_REC *bar) +#define SBAR_ITEM_REDRAW_NEEDED(_bar, _item, _xpos) \ + (((_bar)->dirty_xpos != -1 && \ + (_xpos) >= (_bar)->dirty_xpos) || \ + (_item)->xpos != (_xpos) || (_item)->current_size != (_item)->size) + +static void statusbar_calc_item_positions(STATUSBAR_REC *bar) { WINDOW_REC *old_active_win; GSList *tmp; @@ -237,25 +242,46 @@ static void statusbar_redraw_items(STATUSBAR_REC *bar) statusbar_resize_items(bar, term_width); + /* left-aligned items */ xpos = 0; for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { SBAR_ITEM_REC *rec = tmp->data; if (!rec->config->right_alignment && rec->size > 0) { - rec->xpos = xpos; - xpos += rec->size; - rec->func(rec, FALSE); + if (SBAR_ITEM_REDRAW_NEEDED(bar, rec, xpos)) { + /* redraw the item */ + rec->dirty = TRUE; + if (bar->dirty_xpos == -1 || + xpos < bar->dirty_xpos) { + irssi_set_dirty(); + bar->dirty = TRUE; + bar->dirty_xpos = xpos; + } + + rec->xpos = xpos; + } + xpos += rec->size; } } + /* right-aligned items */ rxpos = term_width; for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { SBAR_ITEM_REC *rec = tmp->data; if (rec->config->right_alignment && rec->size > 0) { - rxpos -= rec->size; - rec->xpos = rxpos; - rec->func(rec, FALSE); + if (SBAR_ITEM_REDRAW_NEEDED(bar, rec, xpos)) { + rec->dirty = TRUE; + if (bar->dirty_xpos == -1 || + xpos < bar->dirty_xpos) { + irssi_set_dirty(); + bar->dirty = TRUE; + bar->dirty_xpos = xpos; + } + rec->xpos = rxpos; + } + + rxpos -= rec->size; } } @@ -276,26 +302,20 @@ static void statusbar_redraw_items(STATUSBAR_REC *bar) return NULL; }*/ -void statusbar_redraw(STATUSBAR_REC *bar) +void statusbar_redraw(STATUSBAR_REC *bar, int force) { - char *str; - - if (bar == NULL) { - if (active_statusbar_group != NULL) { - term_refresh_freeze(); - g_slist_foreach(active_statusbar_group->bars, - (GFunc) statusbar_redraw, NULL); - term_refresh_thaw(); + if (bar != NULL) { + if (force) { + irssi_set_dirty(); + bar->dirty = TRUE; + bar->dirty_xpos = 0; } - return; + statusbar_calc_item_positions(bar); + } else if (active_statusbar_group != NULL) { + g_slist_foreach(active_statusbar_group->bars, + (GFunc) statusbar_redraw, + GINT_TO_POINTER(force)); } - - str = g_strconcat(bar->color, "%>", NULL); - gui_printtext(0, bar->real_ypos, str); - g_free(str); - - statusbar_redraw_items(bar); - term_refresh(NULL); } void statusbar_item_redraw(SBAR_ITEM_REC *item) @@ -309,15 +329,15 @@ void statusbar_item_redraw(SBAR_ITEM_REC *item) active_win = item->bar->parent_window->active; item->func(item, TRUE); + + item->dirty = TRUE; + item->bar->dirty = TRUE; + irssi_set_dirty(); + if (item->max_size != item->size) { /* item wants a new size - we'll need to redraw the statusbar to see if this is allowed */ - /*FIXME:fprintf(stderr, "%s resizes & redraws whole statusbar", item->config->name);*/ - statusbar_redraw(item->bar); - } else { - /*FIXME:fprintf(stderr, "%s redrawing", item->config->name);*/ - item->func(item, FALSE); - term_refresh(NULL); + statusbar_redraw(item->bar, FALSE); } active_win = old_active_win; @@ -374,7 +394,7 @@ static void statusbars_recalc_ypos(STATUSBAR_REC *bar) if (bar->real_ypos != ypos) { bar->real_ypos = ypos; - statusbar_redraw(bar); + statusbar_redraw(bar, TRUE); } ypos++; @@ -439,6 +459,10 @@ STATUSBAR_REC *statusbar_create(STATUSBAR_GROUP_REC *group, bar->config = config; bar->parent_window = parent_window; + irssi_set_dirty(); + bar->dirty = TRUE; + bar->dirty_xpos = 0; + signal_remove("terminal resized", (SIGNAL_FUNC) sig_terminal_resized); signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized); signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized); @@ -554,7 +578,7 @@ void statusbar_recreate_items(STATUSBAR_REC *bar) statusbar_item_create(bar, rec); } - statusbar_redraw(bar); + statusbar_redraw(bar, TRUE); } void statusbars_recreate_items(void) @@ -835,6 +859,10 @@ SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar, items = g_slist_append(items, rec); g_hash_table_insert(named_sbar_items, config->name, items); + irssi_set_dirty(); + rec->dirty = TRUE; + bar->dirty = TRUE; + signal_emit("statusbar item created", 1, rec); return rec; } @@ -893,6 +921,52 @@ void statusbar_item_destroy(SBAR_ITEM_REC *item) g_free(item); } +static void statusbar_redraw_needed_items(STATUSBAR_REC *bar) +{ + WINDOW_REC *old_active_win; + GSList *tmp; + char *str; + + old_active_win = active_win; + if (bar->parent_window != NULL) + active_win = bar->parent_window->active; + + if (bar->dirty_xpos >= 0) { + str = g_strconcat(bar->color, "%>", NULL); + gui_printtext(bar->dirty_xpos, bar->real_ypos, str); + g_free(str); + } + + for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { + SBAR_ITEM_REC *rec = tmp->data; + + if (rec->dirty || + (bar->dirty_xpos != -1 && + rec->xpos >= bar->dirty_xpos)) { + rec->current_size = rec->size; + rec->func(rec, FALSE); + rec->dirty = FALSE; + } + } + + active_win = old_active_win; +} + +void statusbar_redraw_dirty(void) +{ + GSList *tmp; + + for (tmp = active_statusbar_group->bars; tmp != NULL; tmp = tmp->next) { + STATUSBAR_REC *rec = tmp->data; + + if (rec->dirty) { + statusbar_redraw_needed_items(rec); + rec->dirty = FALSE; + rec->dirty_xpos = -1; + } + } +} + #define STATUSBAR_IS_VISIBLE(bar, window) \ ((bar)->visible == STATUSBAR_VISIBLE_ALWAYS || \ (active_mainwin == (window) && \ @@ -927,7 +1001,7 @@ static void statusbars_add_visible(MAIN_WINDOW_REC *window) STATUSBAR_IS_VISIBLE(config, window) && statusbar_find(group, config->name, window) == NULL) { bar = statusbar_create(group, config, window); - statusbar_redraw(bar); + statusbar_redraw(bar, TRUE); } } } @@ -951,10 +1025,8 @@ static void sig_window_changed(void) for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { MAIN_WINDOW_REC *rec = tmp->data; - mainwindow_resize_freeze(rec); statusbars_remove_unvisible(rec); statusbars_add_visible(rec); - mainwindow_resize_thaw(rec); } } diff --git a/src/fe-text/statusbar.h b/src/fe-text/statusbar.h index 08e9ba80..0d61c059 100644 --- a/src/fe-text/statusbar.h +++ b/src/fe-text/statusbar.h @@ -49,6 +49,9 @@ typedef struct { char *color; /* background color */ int real_ypos; /* real Y-position in screen at the moment */ + + int dirty:1; + int dirty_xpos; /* -1 = only redraw some items, >= 0 = redraw all items after from xpos */ } STATUSBAR_REC; typedef struct { @@ -69,6 +72,9 @@ struct SBAR_ITEM_REC { /* what item gets */ int xpos, size; + + int current_size; /* item size currently in screen */ + int dirty:1; }; extern GSList *statusbar_groups; @@ -98,13 +104,15 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, int escape_vars); /* redraw statusbar, NULL = all */ -void statusbar_redraw(STATUSBAR_REC *bar); +void statusbar_redraw(STATUSBAR_REC *bar, int force); void statusbar_item_redraw(SBAR_ITEM_REC *item); void statusbar_items_redraw(const char *name); void statusbar_recreate_items(STATUSBAR_REC *bar); void statusbars_recreate_items(void); +void statusbar_redraw_dirty(void); + void statusbar_init(void); void statusbar_deinit(void); diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c index 1f0e8974..bf9fd22e 100644 --- a/src/fe-text/term-terminfo.c +++ b/src/fe-text/term-terminfo.c @@ -37,6 +37,7 @@ struct _TERM_WINDOW { TERM_WINDOW *root_window; int term_width, term_height; +static int vcx, vcy; static int curs_x, curs_y; static int last_fg, last_bg, last_attrs; static int redraw_needed, redraw_tag; @@ -63,7 +64,8 @@ int term_init(void) struct sigaction act; last_fg = last_bg = -1; - last_attrs = 0; + last_attrs = 0; + vcx = vcy = -1; current_term = terminfo_core_init(stdin, stdout); if (current_term == NULL) @@ -108,6 +110,8 @@ void term_resize(int width, int height) term_height = current_term->height = height; term_window_move(root_window, 0, 0, term_width, term_height); } + + vcx = vcy = -1; } /* Returns TRUE if terminal has colors */ @@ -125,13 +129,14 @@ void term_force_colors(int set) /* Clear screen */ void term_clear(void) { + vcx = vcy = -1; terminfo_clear(); } /* Beep */ void term_beep(void) { - /* FIXME */ + terminfo_beep(current_term); } /* Create a new window in terminal */ @@ -169,14 +174,15 @@ void term_window_clear(TERM_WINDOW *window) terminfo_set_normal(); for (y = 0; y < window->height; y++) { - terminfo_move(0, window->y+y); - terminfo_clrtoeol(); + term_move(window, 0, y); + term_clrtoeol(window); } } /* Scroll window up/down */ void term_window_scroll(TERM_WINDOW *window, int count) { + vcx = vcy = -1; terminfo_scroll(window->y, window->y+window->height-1, count); } @@ -244,17 +250,32 @@ void term_set_color(TERM_WINDOW *window, int col) void term_move(TERM_WINDOW *window, int x, int y) { - terminfo_move(x+window->x, y+window->y); + int newx, newy; + + newx = x+window->x; + newy = y+window->y; + if (vcx != newx || vcy != newy) { + terminfo_move_relative(vcx, vcy, newx, newy); + vcx = newx; vcy = newy; + } } void term_addch(TERM_WINDOW *window, int chr) { - putc(chr, window->term->out); + putc(chr, window->term->out); + if (++vcx == window->width) { + vcx = 0; vcy++; + } } void term_addstr(TERM_WINDOW *window, char *str) { - fputs(str, window->term->out); + fputs(str, window->term->out); + vcx += strlen(str); + while (vcx > window->width) { + vcx -= window->width; + vcy++; + } } void term_clrtoeol(TERM_WINDOW *window) @@ -270,7 +291,8 @@ void term_move_cursor(int x, int y) void term_refresh(TERM_WINDOW *window) { - terminfo_move(curs_x, curs_y); + if (vcx != curs_x || vcy != curs_y) + term_move(root_window, curs_x, curs_y); fflush(window != NULL ? window->term->out : current_term->out); } diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c index 08c76d10..3dee2ffc 100644 --- a/src/fe-text/terminfo-core.c +++ b/src/fe-text/terminfo-core.c @@ -61,8 +61,8 @@ static TERMINFO_REC tcaps[] = { { "cup", "cm", CAP_TYPE_STR, &temp_term.TI_cup }, { "hpa", "ch", CAP_TYPE_STR, &temp_term.TI_hpa }, { "vpa", "vh", CAP_TYPE_STR, &temp_term.TI_vpa }, - { "xvpa", "YD", CAP_TYPE_FLAG, &temp_term.TI_xvpa }, - { "hvpa", "YA", CAP_TYPE_FLAG, &temp_term.TI_xhpa }, + { "cub1", "le", CAP_TYPE_STR, &temp_term.TI_cub1 }, + { "cuf1", "nd", CAP_TYPE_STR, &temp_term.TI_cuf1 }, /* Scrolling */ { "csr", "cs", CAP_TYPE_STR, &temp_term.TI_csr }, @@ -113,6 +113,40 @@ static void _move_pa(TERM_REC *term, int x, int y) tput(tparm(term->TI_vpa, y)); } +/* Move cursor from a known position */ +static void _move_relative(TERM_REC *term, int oldx, int oldy, int x, int y) +{ + if (oldx == 0 && x == 0 && y == oldy+1) { + /* move to beginning of next line - + hope this works everywhere */ + tput("\r\n"); + return; + } + + if (oldx > 0 && y == oldy) { + /* move cursor left/right */ + if (x == oldx-1 && term->TI_cub1) { + tput(tparm(term->TI_cub1)); + return; + } + if (x == oldx+1 && y == oldy && term->TI_cuf1) { + tput(tparm(term->TI_cuf1)); + return; + } + } + + /* fallback to absolute positioning */ + if (term->TI_cup) { + tput(tparm(term->TI_cup, y, x)); + return; + } + + if (oldy != y) + tput(tparm(term->TI_vpa, y)); + if (oldx != x) + tput(tparm(term->TI_hpa, x)); +} + #define scroll_region_setup(term, y1, y2) \ if ((term)->TI_csr != NULL) \ tput(tparm((term)->TI_csr, y1, y2)); \ @@ -474,14 +508,15 @@ static int term_setup(TERM_REC *term) /* Cursor movement */ if (term->TI_cup) term->move = _move_cup; - else if (term->TI_hpa && term->TI_vpa && - !term->TI_xhpa && !term->TI_xvpa) + else if (term->TI_hpa && term->TI_vpa) term->move = _move_pa; else { fprintf(term->out, "Terminal doesn't support cursor movement\n"); return 0; } + term->move_relative = _move_relative; + /* Scrolling */ if ((term->TI_csr || term->TI_wind) && term->TI_rin && term->TI_indn) term->scroll = _scroll_region; diff --git a/src/fe-text/terminfo-core.h b/src/fe-text/terminfo-core.h index 480e80c1..4586178d 100644 --- a/src/fe-text/terminfo-core.h +++ b/src/fe-text/terminfo-core.h @@ -4,6 +4,7 @@ #include #define terminfo_move(x, y) current_term->move(current_term, x, y) +#define terminfo_move_relative(oldx, oldy, x, y) current_term->move_relative(current_term, oldx, oldy, x, y) #define terminfo_scroll(y1, y2, count) current_term->scroll(current_term, y1, y2, count) #define terminfo_clear() current_term->clear(current_term) #define terminfo_clrtoeol() current_term->clrtoeol(current_term) @@ -14,12 +15,14 @@ #define terminfo_set_uline(set) current_term->set_uline(current_term, set) #define terminfo_set_standout(set) current_term->set_standout(current_term, set) #define terminfo_has_colors(term) (term->TI_fg[0] != NULL) +#define terminfo_beep(term) current_term->beep(current_term) typedef struct _TERM_REC TERM_REC; struct _TERM_REC { /* Functions */ void (*move)(TERM_REC *term, int x, int y); + void (*move_relative)(TERM_REC *term, int oldx, int oldy, int x, int y); void (*scroll)(TERM_REC *term, int y1, int y2, int count); void (*clear)(TERM_REC *term); @@ -45,8 +48,7 @@ struct _TERM_REC { /* Cursor movement */ const char *TI_smcup, *TI_rmcup, *TI_cup; - const char *TI_hpa, *TI_vpa; - int TI_xhpa, TI_xvpa; + const char *TI_hpa, *TI_vpa, *TI_cub1, *TI_cuf1; /* Scrolling */ const char *TI_csr, *TI_wind; diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index cc33f715..540721e7 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -307,6 +307,9 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, char *tmp; int xpos, color, drawcount, first; + if (view->dirty) /* don't bother drawing anything - redraw is coming */ + return 0; + cache = textbuffer_view_get_line_cache(view, line); if (subline >= cache->count) return 0; @@ -581,10 +584,13 @@ static int view_get_linecount_all(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) } static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, - int subline, int ypos, int lines) + int subline, int ypos, int lines, int fill_bottom) { int linecount; + if (view->dirty) /* don't bother drawing anything - redraw is coming */ + return; + while (line != NULL && lines > 0) { linecount = view_line_draw(view, line, subline, ypos, lines); ypos += linecount; lines -= linecount; @@ -593,17 +599,20 @@ static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, line = line->next; } - /* clear the rest of the view */ - term_set_color(view->window, ATTR_RESET); - while (lines > 0) { - term_move(view->window, 0, ypos); - term_clrtoeol(view->window); - ypos++; lines--; + if (fill_bottom) { + /* clear the rest of the view */ + term_set_color(view->window, ATTR_RESET); + while (lines > 0) { + term_move(view->window, 0, ypos); + term_clrtoeol(view->window); + ypos++; lines--; + } } } -#define view_draw_top(view, lines) \ - view_draw(view, (view)->startline, (view)->subline, 0, lines) +#define view_draw_top(view, lines, fill_bottom) \ + view_draw(view, (view)->startline, (view)->subline, \ + 0, lines, fill_bottom) static void view_draw_bottom(TEXT_BUFFER_VIEW_REC *view, int lines) { @@ -622,7 +631,7 @@ static void view_draw_bottom(TEXT_BUFFER_VIEW_REC *view, int lines) line = line->next; } - view_draw(view, line, subline, maxline, lines); + view_draw(view, line, subline, maxline, lines, TRUE); } /* Returns number of lines actually scrolled */ @@ -687,7 +696,7 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines, if (draw_nonclean) { if (realcount < 0) - view_draw_top(view, -realcount); + view_draw_top(view, -realcount, TRUE); else view_draw_bottom(view, realcount); } @@ -760,7 +769,7 @@ void textbuffer_view_resize(TEXT_BUFFER_VIEW_REC *view, int width, int height) view->empty_linecount = view->height-linecount; } - textbuffer_view_redraw(view); + view->dirty = TRUE; } /* Clear the view, don't actually remove any lines from buffer. */ @@ -1154,8 +1163,8 @@ void textbuffer_view_set_window(TEXT_BUFFER_VIEW_REC *view, if (view->window != window) { view->window = window; - if (window != NULL) - textbuffer_view_redraw(view); + if (window != NULL) + view->dirty = TRUE; } } @@ -1165,8 +1174,9 @@ void textbuffer_view_redraw(TEXT_BUFFER_VIEW_REC *view) g_return_if_fail(view != NULL); if (view->window != NULL) { + view->dirty = FALSE; term_window_clear(view->window); - view_draw_top(view, view->height); + view_draw_top(view, view->height, FALSE); term_refresh(view->window); } } diff --git a/src/fe-text/textbuffer-view.h b/src/fe-text/textbuffer-view.h index e8b1262d..497a980d 100644 --- a/src/fe-text/textbuffer-view.h +++ b/src/fe-text/textbuffer-view.h @@ -71,6 +71,8 @@ struct _TEXT_BUFFER_VIEW_REC { int empty_linecount; /* window is at the bottom of the text buffer */ unsigned int bottom:1; + /* Window needs a redraw */ + unsigned int dirty:1; /* Bookmarks to the lines in the buffer - removed automatically when the line gets removed from buffer */