diff options
Diffstat (limited to 'tools/perf/util/ui/browser.c')
-rw-r--r-- | tools/perf/util/ui/browser.c | 228 |
1 files changed, 155 insertions, 73 deletions
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 611219f..a54b926 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -1,4 +1,7 @@ +#include "../util.h" +#include "../../perf.h" #include "libslang.h" +#include <newt.h> #include "ui.h" #include <linux/compiler.h> #include <linux/list.h> @@ -8,8 +11,8 @@ #include "browser.h" #include "helpline.h" #include "../color.h" -#include "../util.h" -#include <stdio.h> + +int newtGetKey(void); static int ui_browser__percent_color(double percent, bool current) { @@ -39,31 +42,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x) SLsmg_gotorc(self->y + y, self->x + x); } +static struct list_head * +ui_browser__list_head_filter_entries(struct ui_browser *browser, + struct list_head *pos) +{ + do { + if (!browser->filter || !browser->filter(browser, pos)) + return pos; + pos = pos->next; + } while (pos != browser->entries); + + return NULL; +} + +static struct list_head * +ui_browser__list_head_filter_prev_entries(struct ui_browser *browser, + struct list_head *pos) +{ + do { + if (!browser->filter || !browser->filter(browser, pos)) + return pos; + pos = pos->prev; + } while (pos != browser->entries); + + return NULL; +} + void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) { struct list_head *head = self->entries; struct list_head *pos; + if (self->nr_entries == 0) + return; + switch (whence) { case SEEK_SET: - pos = head->next; + pos = ui_browser__list_head_filter_entries(self, head->next); break; case SEEK_CUR: pos = self->top; break; case SEEK_END: - pos = head->prev; + pos = ui_browser__list_head_filter_prev_entries(self, head->prev); break; default: return; } + assert(pos != NULL); + if (offset > 0) { while (offset-- != 0) - pos = pos->next; + pos = ui_browser__list_head_filter_entries(self, pos->next); } else { while (offset++ != 0) - pos = pos->prev; + pos = ui_browser__list_head_filter_prev_entries(self, pos->prev); } self->top = pos; @@ -127,11 +161,8 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) void ui_browser__refresh_dimensions(struct ui_browser *self) { - int cols, rows; - newtGetScreenSize(&cols, &rows); - - self->width = cols - 1; - self->height = rows - 2; + self->width = SLtt_Screen_Cols - 1; + self->height = SLtt_Screen_Rows - 2; self->y = 1; self->x = 0; } @@ -142,26 +173,11 @@ void ui_browser__reset_index(struct ui_browser *self) self->seek(self, 0, SEEK_SET); } -void ui_browser__add_exit_key(struct ui_browser *self, int key) -{ - newtFormAddHotKey(self->form, key); -} - -void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) -{ - int i = 0; - - while (keys[i] && i < 64) { - ui_browser__add_exit_key(self, keys[i]); - ++i; - } -} - void __ui_browser__show_title(struct ui_browser *browser, const char *title) { SLsmg_gotorc(0, 0); ui_browser__set_color(browser, NEWT_COLORSET_ROOT); - slsmg_write_nstring(title, browser->width); + slsmg_write_nstring(title, browser->width + 1); } void ui_browser__show_title(struct ui_browser *browser, const char *title) @@ -174,77 +190,143 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title) int ui_browser__show(struct ui_browser *self, const char *title, const char *helpline, ...) { + int err; va_list ap; - int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP, - NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ', - NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 }; - - if (self->form != NULL) - newtFormDestroy(self->form); ui_browser__refresh_dimensions(self); - self->form = newtForm(NULL, NULL, 0); - if (self->form == NULL) - return -1; - - self->sb = newtVerticalScrollbar(self->width, 1, self->height, - HE_COLORSET_NORMAL, - HE_COLORSET_SELECTED); - if (self->sb == NULL) - return -1; pthread_mutex_lock(&ui__lock); __ui_browser__show_title(self, title); - ui_browser__add_exit_keys(self, keys); - newtFormAddComponent(self->form, self->sb); + self->title = title; + free(self->helpline); + self->helpline = NULL; va_start(ap, helpline); - ui_helpline__vpush(helpline, ap); + err = vasprintf(&self->helpline, helpline, ap); va_end(ap); + if (err > 0) + ui_helpline__push(self->helpline); pthread_mutex_unlock(&ui__lock); - return 0; + return err ? 0 : -1; } -void ui_browser__hide(struct ui_browser *self) +void ui_browser__hide(struct ui_browser *browser __used) { pthread_mutex_lock(&ui__lock); - newtFormDestroy(self->form); - self->form = NULL; ui_helpline__pop(); pthread_mutex_unlock(&ui__lock); } -int ui_browser__refresh(struct ui_browser *self) +static void ui_browser__scrollbar_set(struct ui_browser *browser) +{ + int height = browser->height, h = 0, pct = 0, + col = browser->width, + row = browser->y - 1; + + if (browser->nr_entries > 1) { + pct = ((browser->index * (browser->height - 1)) / + (browser->nr_entries - 1)); + } + + while (h < height) { + ui_browser__gotorc(browser, row++, col); + SLsmg_set_char_set(1); + SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR); + SLsmg_set_char_set(0); + ++h; + } +} + +static int __ui_browser__refresh(struct ui_browser *browser) { int row; + row = browser->refresh(browser); + ui_browser__set_color(browser, HE_COLORSET_NORMAL); + SLsmg_fill_region(browser->y + row, browser->x, + browser->height - row, browser->width, ' '); + ui_browser__scrollbar_set(browser); + + return 0; +} + +int ui_browser__refresh(struct ui_browser *browser) +{ pthread_mutex_lock(&ui__lock); - newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); - row = self->refresh(self); - ui_browser__set_color(self, HE_COLORSET_NORMAL); - SLsmg_fill_region(self->y + row, self->x, - self->height - row, self->width, ' '); + __ui_browser__refresh(browser); pthread_mutex_unlock(&ui__lock); return 0; } -int ui_browser__run(struct ui_browser *self) +/* + * Here we're updating nr_entries _after_ we started browsing, i.e. we have to + * forget about any reference to any entry in the underlying data structure, + * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser + * after an output_resort and hist decay. + */ +void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) +{ + off_t offset = nr_entries - browser->nr_entries; + + browser->nr_entries = nr_entries; + + if (offset < 0) { + if (browser->top_idx < (u64)-offset) + offset = -browser->top_idx; + + browser->index += offset; + browser->top_idx += offset; + } + + browser->top = NULL; + browser->seek(browser, browser->top_idx, SEEK_SET); +} + +int ui_browser__run(struct ui_browser *self, int delay_secs) { - struct newtExitStruct es; + int err, key; + struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; - if (ui_browser__refresh(self) < 0) - return -1; + pthread__unblock_sigwinch(); while (1) { off_t offset; + fd_set read_set; - newtFormRun(self->form, &es); + pthread_mutex_lock(&ui__lock); + err = __ui_browser__refresh(self); + SLsmg_refresh(); + pthread_mutex_unlock(&ui__lock); + if (err < 0) + break; + + FD_ZERO(&read_set); + FD_SET(0, &read_set); + + if (delay_secs) { + timeout.tv_sec = delay_secs; + timeout.tv_usec = 0; + } - if (es.reason != NEWT_EXIT_HOTKEY) + err = select(1, &read_set, NULL, NULL, ptimeout); + if (err > 0 && FD_ISSET(0, &read_set)) + key = newtGetKey(); + else if (err == 0) break; - switch (es.u.key) { + else { + pthread_mutex_lock(&ui__lock); + SLtt_get_screen_size(); + SLsmg_reinit_smg(); + pthread_mutex_unlock(&ui__lock); + ui_browser__refresh_dimensions(self); + __ui_browser__show_title(self, self->title); + ui_helpline__puts(self->helpline); + continue; + } + + switch (key) { case NEWT_KEY_DOWN: if (self->index == self->nr_entries - 1) break; @@ -301,10 +383,8 @@ int ui_browser__run(struct ui_browser *self) self->seek(self, -offset, SEEK_END); break; default: - return es.u.key; + return key; } - if (ui_browser__refresh(self) < 0) - return -1; } return -1; } @@ -316,27 +396,29 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self) int row = 0; if (self->top == NULL || self->top == self->entries) - self->top = head->next; + self->top = ui_browser__list_head_filter_entries(self, head->next); pos = self->top; list_for_each_from(pos, head) { - ui_browser__gotorc(self, row, 0); - self->write(self, pos, row); - if (++row == self->height) - break; + if (!self->filter || !self->filter(self, pos)) { + ui_browser__gotorc(self, row, 0); + self->write(self, pos, row); + if (++row == self->height) + break; + } } return row; } -static struct newtPercentTreeColors { +static struct ui_browser__colors { const char *topColorFg, *topColorBg; const char *mediumColorFg, *mediumColorBg; const char *normalColorFg, *normalColorBg; const char *selColorFg, *selColorBg; const char *codeColorFg, *codeColorBg; -} defaultPercentTreeColors = { +} ui_browser__default_colors = { "red", "lightgray", "green", "lightgray", "black", "lightgray", @@ -346,7 +428,7 @@ static struct newtPercentTreeColors { void ui_browser__init(void) { - struct newtPercentTreeColors *c = &defaultPercentTreeColors; + struct ui_browser__colors *c = &ui_browser__default_colors; sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); |