5 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
6 * the build if it isn't defined. Use the equivalent one that glibc
10 #ifndef HAVE_LONG_LONG
11 #define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
16 #include <sys/ttydefaults.h>
25 #if SLANG_VERSION < 20104
26 #define slsmg_printf(msg, args...) SLsmg_printf((char *)msg, ##args)
27 #define slsmg_write_nstring(msg, len) SLsmg_write_nstring((char *)msg, len)
28 #define sltt_set_color(obj, name, fg, bg) SLtt_set_color(obj,(char *)name,\
29 (char *)fg, (char *)bg)
31 #define slsmg_printf SLsmg_printf
32 #define slsmg_write_nstring SLsmg_write_nstring
33 #define sltt_set_color SLtt_set_color
37 newtComponent form
, scale
;
40 struct ui_progress
*ui_progress__new(const char *title
, u64 total
)
42 struct ui_progress
*self
= malloc(sizeof(*self
));
49 newtGetScreenSize(&cols
, NULL
);
51 newtCenteredWindow(cols
, 1, title
);
52 self
->form
= newtForm(NULL
, NULL
, 0);
53 if (self
->form
== NULL
)
55 self
->scale
= newtScale(0, 0, cols
, total
);
56 if (self
->scale
== NULL
)
58 newtFormAddComponent(self
->form
, self
->scale
);
65 newtFormDestroy(self
->form
);
71 void ui_progress__update(struct ui_progress
*self
, u64 curr
)
74 * FIXME: We should have a per UI backend way of showing progress,
75 * stdio will just show a percentage as NN%, etc.
79 newtScaleSet(self
->scale
, curr
);
83 void ui_progress__delete(struct ui_progress
*self
)
85 if (use_browser
> 0) {
86 newtFormDestroy(self
->form
);
92 static void ui_helpline__pop(void)
97 static void ui_helpline__push(const char *msg
)
99 newtPushHelpLine(msg
);
102 static void ui_helpline__vpush(const char *fmt
, va_list ap
)
106 if (vasprintf(&s
, fmt
, ap
) < 0)
107 vfprintf(stderr
, fmt
, ap
);
109 ui_helpline__push(s
);
114 static void ui_helpline__fpush(const char *fmt
, ...)
119 ui_helpline__vpush(fmt
, ap
);
123 static void ui_helpline__puts(const char *msg
)
126 ui_helpline__push(msg
);
129 static char browser__last_msg
[1024];
131 int browser__show_help(const char *format
, va_list ap
)
136 ret
= vsnprintf(browser__last_msg
+ backlog
,
137 sizeof(browser__last_msg
) - backlog
, format
, ap
);
140 if (browser__last_msg
[backlog
- 1] == '\n') {
141 ui_helpline__puts(browser__last_msg
);
149 static void newt_form__set_exit_keys(newtComponent self
)
151 newtFormAddHotKey(self
, NEWT_KEY_LEFT
);
152 newtFormAddHotKey(self
, NEWT_KEY_ESCAPE
);
153 newtFormAddHotKey(self
, 'Q');
154 newtFormAddHotKey(self
, 'q');
155 newtFormAddHotKey(self
, CTRL('c'));
158 static newtComponent
newt_form__new(void)
160 newtComponent self
= newtForm(NULL
, NULL
, 0);
162 newt_form__set_exit_keys(self
);
166 static int popup_menu(int argc
, char * const argv
[])
168 struct newtExitStruct es
;
169 int i
, rc
= -1, max_len
= 5;
170 newtComponent listbox
, form
= newt_form__new();
175 listbox
= newtListbox(0, 0, argc
, NEWT_FLAG_RETURNEXIT
);
177 goto out_destroy_form
;
179 newtFormAddComponent(form
, listbox
);
181 for (i
= 0; i
< argc
; ++i
) {
182 int len
= strlen(argv
[i
]);
185 if (newtListboxAddEntry(listbox
, argv
[i
], (void *)(long)i
))
186 goto out_destroy_form
;
189 newtCenteredWindow(max_len
, argc
, NULL
);
190 newtFormRun(form
, &es
);
191 rc
= newtListboxGetCurrent(listbox
) - NULL
;
192 if (es
.reason
== NEWT_EXIT_HOTKEY
)
196 newtFormDestroy(form
);
200 static int ui__help_window(const char *text
)
202 struct newtExitStruct es
;
203 newtComponent tb
, form
= newt_form__new();
205 int max_len
= 0, nr_lines
= 0;
213 const char *sep
= strchr(t
, '\n');
217 sep
= strchr(t
, '\0');
227 tb
= newtTextbox(0, 0, max_len
, nr_lines
, 0);
229 goto out_destroy_form
;
231 newtTextboxSetText(tb
, text
);
232 newtFormAddComponent(form
, tb
);
233 newtCenteredWindow(max_len
, nr_lines
, NULL
);
234 newtFormRun(form
, &es
);
238 newtFormDestroy(form
);
242 static bool dialog_yesno(const char *msg
)
244 /* newtWinChoice should really be accepting const char pointers... */
245 char yes
[] = "Yes", no
[] = "No";
246 return newtWinChoice(NULL
, yes
, no
, (char *)msg
) == 1;
249 static void ui__error_window(const char *fmt
, ...)
254 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt
, ap
);
258 #define HE_COLORSET_TOP 50
259 #define HE_COLORSET_MEDIUM 51
260 #define HE_COLORSET_NORMAL 52
261 #define HE_COLORSET_SELECTED 53
262 #define HE_COLORSET_CODE 54
264 static int ui_browser__percent_color(double percent
, bool current
)
267 return HE_COLORSET_SELECTED
;
268 if (percent
>= MIN_RED
)
269 return HE_COLORSET_TOP
;
270 if (percent
>= MIN_GREEN
)
271 return HE_COLORSET_MEDIUM
;
272 return HE_COLORSET_NORMAL
;
276 newtComponent form
, sb
;
277 u64 index
, first_visible_entry_idx
;
278 void *first_visible_entry
, *entries
;
279 u16 top
, left
, width
, height
;
284 static void ui_browser__refresh_dimensions(struct ui_browser
*self
)
287 newtGetScreenSize(&cols
, &rows
);
289 if (self
->width
> cols
- 4)
290 self
->width
= cols
- 4;
291 self
->height
= rows
- 5;
292 if (self
->height
> self
->nr_entries
)
293 self
->height
= self
->nr_entries
;
294 self
->top
= (rows
- self
->height
) / 2;
295 self
->left
= (cols
- self
->width
) / 2;
298 static void ui_browser__reset_index(struct ui_browser
*self
)
300 self
->index
= self
->first_visible_entry_idx
= 0;
301 self
->first_visible_entry
= NULL
;
304 static int objdump_line__show(struct objdump_line
*self
, struct list_head
*head
,
305 int width
, struct hist_entry
*he
, int len
,
308 if (self
->offset
!= -1) {
309 struct symbol
*sym
= he
->ms
.sym
;
310 unsigned int hits
= 0;
311 double percent
= 0.0;
313 struct sym_priv
*priv
= symbol__priv(sym
);
314 struct sym_ext
*sym_ext
= priv
->ext
;
315 struct sym_hist
*h
= priv
->hist
;
316 s64 offset
= self
->offset
;
317 struct objdump_line
*next
= objdump__get_next_ip_line(head
, self
);
319 while (offset
< (s64
)len
&&
320 (next
== NULL
|| offset
< next
->offset
)) {
322 percent
+= sym_ext
[offset
].percent
;
324 hits
+= h
->ip
[offset
];
329 if (sym_ext
== NULL
&& h
->sum
)
330 percent
= 100.0 * hits
/ h
->sum
;
332 color
= ui_browser__percent_color(percent
, current_entry
);
333 SLsmg_set_color(color
);
334 slsmg_printf(" %7.2f ", percent
);
336 SLsmg_set_color(HE_COLORSET_CODE
);
338 int color
= ui_browser__percent_color(0, current_entry
);
339 SLsmg_set_color(color
);
340 slsmg_write_nstring(" ", 9);
343 SLsmg_write_char(':');
344 slsmg_write_nstring(" ", 8);
346 slsmg_write_nstring(" ", width
- 18);
348 slsmg_write_nstring(self
->line
, width
- 18);
353 static int ui_browser__refresh_entries(struct ui_browser
*self
)
355 struct objdump_line
*pos
;
356 struct list_head
*head
= self
->entries
;
357 struct hist_entry
*he
= self
->priv
;
359 int len
= he
->ms
.sym
->end
- he
->ms
.sym
->start
;
361 if (self
->first_visible_entry
== NULL
|| self
->first_visible_entry
== self
->entries
)
362 self
->first_visible_entry
= head
->next
;
364 pos
= list_entry(self
->first_visible_entry
, struct objdump_line
, node
);
366 list_for_each_entry_from(pos
, head
, node
) {
367 bool current_entry
= (self
->first_visible_entry_idx
+ row
) == self
->index
;
368 SLsmg_gotorc(self
->top
+ row
, self
->left
);
369 objdump_line__show(pos
, head
, self
->width
,
370 he
, len
, current_entry
);
371 if (++row
== self
->height
)
375 SLsmg_set_color(HE_COLORSET_NORMAL
);
376 SLsmg_fill_region(self
->top
+ row
, self
->left
,
377 self
->height
- row
, self
->width
, ' ');
382 static int ui_browser__run(struct ui_browser
*self
, const char *title
,
383 struct newtExitStruct
*es
)
386 newtFormDestroy(self
->form
);
390 ui_browser__refresh_dimensions(self
);
391 newtCenteredWindow(self
->width
+ 2, self
->height
, title
);
392 self
->form
= newt_form__new();
393 if (self
->form
== NULL
)
396 self
->sb
= newtVerticalScrollbar(self
->width
+ 1, 0, self
->height
,
398 HE_COLORSET_SELECTED
);
399 if (self
->sb
== NULL
)
402 newtFormAddHotKey(self
->form
, NEWT_KEY_UP
);
403 newtFormAddHotKey(self
->form
, NEWT_KEY_DOWN
);
404 newtFormAddHotKey(self
->form
, NEWT_KEY_PGUP
);
405 newtFormAddHotKey(self
->form
, NEWT_KEY_PGDN
);
406 newtFormAddHotKey(self
->form
, ' ');
407 newtFormAddHotKey(self
->form
, NEWT_KEY_HOME
);
408 newtFormAddHotKey(self
->form
, NEWT_KEY_END
);
409 newtFormAddHotKey(self
->form
, NEWT_KEY_TAB
);
410 newtFormAddHotKey(self
->form
, NEWT_KEY_RIGHT
);
412 if (ui_browser__refresh_entries(self
) < 0)
414 newtFormAddComponent(self
->form
, self
->sb
);
419 newtFormRun(self
->form
, es
);
421 if (es
->reason
!= NEWT_EXIT_HOTKEY
)
423 if (is_exit_key(es
->u
.key
))
427 if (self
->index
== self
->nr_entries
- 1)
430 if (self
->index
== self
->first_visible_entry_idx
+ self
->height
) {
431 struct list_head
*pos
= self
->first_visible_entry
;
432 ++self
->first_visible_entry_idx
;
433 self
->first_visible_entry
= pos
->next
;
437 if (self
->index
== 0)
440 if (self
->index
< self
->first_visible_entry_idx
) {
441 struct list_head
*pos
= self
->first_visible_entry
;
442 --self
->first_visible_entry_idx
;
443 self
->first_visible_entry
= pos
->prev
;
448 if (self
->first_visible_entry_idx
+ self
->height
> self
->nr_entries
- 1)
451 offset
= self
->height
;
452 if (self
->index
+ offset
> self
->nr_entries
- 1)
453 offset
= self
->nr_entries
- 1 - self
->index
;
454 self
->index
+= offset
;
455 self
->first_visible_entry_idx
+= offset
;
458 struct list_head
*pos
= self
->first_visible_entry
;
459 self
->first_visible_entry
= pos
->next
;
464 if (self
->first_visible_entry_idx
== 0)
467 if (self
->first_visible_entry_idx
< self
->height
)
468 offset
= self
->first_visible_entry_idx
;
470 offset
= self
->height
;
472 self
->index
-= offset
;
473 self
->first_visible_entry_idx
-= offset
;
476 struct list_head
*pos
= self
->first_visible_entry
;
477 self
->first_visible_entry
= pos
->prev
;
481 ui_browser__reset_index(self
);
484 struct list_head
*head
= self
->entries
;
485 offset
= self
->height
- 1;
487 if (offset
> self
->nr_entries
)
488 offset
= self
->nr_entries
;
490 self
->index
= self
->first_visible_entry_idx
= self
->nr_entries
- 1 - offset
;
491 self
->first_visible_entry
= head
->prev
;
492 while (offset
-- != 0) {
493 struct list_head
*pos
= self
->first_visible_entry
;
494 self
->first_visible_entry
= pos
->prev
;
505 if (ui_browser__refresh_entries(self
) < 0)
512 * When debugging newt problems it was useful to be able to "unroll"
513 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
514 * a source file with the sequence of calls to these methods, to then
515 * tweak the arrays to get the intended results, so I'm keeping this code
516 * here, may be useful again in the future.
520 static void newt_checkbox_tree__add(newtComponent tree
, const char *str
,
521 void *priv
, int *indexes
)
524 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
525 int i
= 0, len
= 40 - strlen(str
);
528 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
529 len
, len
, " ", str
, priv
);
530 while (indexes
[i
] != NEWT_ARG_LAST
) {
531 if (indexes
[i
] != NEWT_ARG_APPEND
)
532 fprintf(stderr
, " %d,", indexes
[i
]);
534 fprintf(stderr
, " %s,", "NEWT_ARG_APPEND");
537 fprintf(stderr
, " %s", " NEWT_ARG_LAST);\n");
540 newtCheckboxTreeAddArray(tree
, str
, priv
, 0, indexes
);
543 static char *callchain_list__sym_name(struct callchain_list
*self
,
544 char *bf
, size_t bfsize
)
547 return self
->ms
.sym
->name
;
549 snprintf(bf
, bfsize
, "%#Lx", self
->ip
);
553 static void __callchain__append_graph_browser(struct callchain_node
*self
,
554 newtComponent tree
, u64 total
,
555 int *indexes
, int depth
)
557 struct rb_node
*node
;
558 u64 new_total
, remaining
;
561 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
562 new_total
= self
->children_hit
;
566 remaining
= new_total
;
567 node
= rb_first(&self
->rb_root
);
569 struct callchain_node
*child
= rb_entry(node
, struct callchain_node
, rb_node
);
570 struct rb_node
*next
= rb_next(node
);
571 u64 cumul
= cumul_hits(child
);
572 struct callchain_list
*chain
;
573 int first
= true, printed
= 0;
577 indexes
[depth
] = NEWT_ARG_APPEND
;
578 indexes
[depth
+ 1] = NEWT_ARG_LAST
;
580 list_for_each_entry(chain
, &child
->val
, list
) {
581 char ipstr
[BITS_PER_LONG
/ 4 + 1],
583 const char *str
= callchain_list__sym_name(chain
, ipstr
, sizeof(ipstr
));
586 double percent
= cumul
* 100.0 / new_total
;
589 if (asprintf(&alloc_str
, "%2.2f%% %s", percent
, str
) < 0)
590 str
= "Not enough memory!";
594 indexes
[depth
] = idx
;
595 indexes
[depth
+ 1] = NEWT_ARG_APPEND
;
596 indexes
[depth
+ 2] = NEWT_ARG_LAST
;
599 newt_checkbox_tree__add(tree
, str
, &chain
->ms
, indexes
);
604 indexes
[depth
] = idx
;
606 indexes
[depth
+ 1] = chain_idx
;
609 __callchain__append_graph_browser(child
, tree
, new_total
, indexes
,
610 depth
+ (chain_idx
!= -1 ? 2 : 1));
615 static void callchain__append_graph_browser(struct callchain_node
*self
,
616 newtComponent tree
, u64 total
,
617 int *indexes
, int parent_idx
)
619 struct callchain_list
*chain
;
622 indexes
[1] = NEWT_ARG_APPEND
;
623 indexes
[2] = NEWT_ARG_LAST
;
625 list_for_each_entry(chain
, &self
->val
, list
) {
626 char ipstr
[BITS_PER_LONG
/ 4 + 1], *str
;
628 if (chain
->ip
>= PERF_CONTEXT_MAX
)
631 if (!i
++ && sort__first_dimension
== SORT_SYM
)
634 str
= callchain_list__sym_name(chain
, ipstr
, sizeof(ipstr
));
635 newt_checkbox_tree__add(tree
, str
, &chain
->ms
, indexes
);
638 indexes
[1] = parent_idx
;
639 indexes
[2] = NEWT_ARG_APPEND
;
640 indexes
[3] = NEWT_ARG_LAST
;
641 __callchain__append_graph_browser(self
, tree
, total
, indexes
, 2);
644 static void hist_entry__append_callchain_browser(struct hist_entry
*self
,
645 newtComponent tree
, u64 total
, int parent_idx
)
647 struct rb_node
*rb_node
;
648 int indexes
[1024] = { [0] = parent_idx
, };
650 struct callchain_node
*chain
;
652 rb_node
= rb_first(&self
->sorted_chain
);
654 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
655 switch (callchain_param
.mode
) {
658 case CHAIN_GRAPH_ABS
: /* falldown */
659 case CHAIN_GRAPH_REL
:
660 callchain__append_graph_browser(chain
, tree
, total
, indexes
, idx
++);
666 rb_node
= rb_next(rb_node
);
670 static size_t hist_entry__append_browser(struct hist_entry
*self
,
671 newtComponent tree
, u64 total
)
676 if (symbol_conf
.exclude_other
&& !self
->parent
)
679 ret
= hist_entry__snprintf(self
, s
, sizeof(s
), NULL
,
680 false, 0, false, total
);
681 if (symbol_conf
.use_callchain
) {
684 indexes
[0] = NEWT_ARG_APPEND
;
685 indexes
[1] = NEWT_ARG_LAST
;
686 newt_checkbox_tree__add(tree
, s
, &self
->ms
, indexes
);
688 newtListboxAppendEntry(tree
, s
, &self
->ms
);
693 int hist_entry__tui_annotate(struct hist_entry
*self
)
695 struct ui_browser browser
;
696 struct newtExitStruct es
;
697 struct objdump_line
*pos
, *n
;
701 if (self
->ms
.sym
== NULL
)
704 if (self
->ms
.map
->dso
->annotate_warned
)
707 if (hist_entry__annotate(self
, &head
) < 0) {
708 ui__error_window(browser__last_msg
);
712 ui_helpline__push("Press <- or ESC to exit");
714 memset(&browser
, 0, sizeof(browser
));
715 browser
.entries
= &head
;
717 list_for_each_entry(pos
, &head
, node
) {
718 size_t line_len
= strlen(pos
->line
);
719 if (browser
.width
< line_len
)
720 browser
.width
= line_len
;
721 ++browser
.nr_entries
;
724 browser
.width
+= 18; /* Percentage */
725 ret
= ui_browser__run(&browser
, self
->ms
.sym
->name
, &es
);
726 newtFormDestroy(browser
.form
);
728 list_for_each_entry_safe(pos
, n
, &head
, node
) {
729 list_del(&pos
->node
);
730 objdump_line__free(pos
);
736 static const void *newt__symbol_tree_get_current(newtComponent self
)
738 if (symbol_conf
.use_callchain
)
739 return newtCheckboxTreeGetCurrent(self
);
740 return newtListboxGetCurrent(self
);
743 static void hist_browser__selection(newtComponent self
, void *data
)
745 const struct map_symbol
**symbol_ptr
= data
;
746 *symbol_ptr
= newt__symbol_tree_get_current(self
);
749 struct hist_browser
{
750 newtComponent form
, tree
;
751 const struct map_symbol
*selection
;
754 static struct hist_browser
*hist_browser__new(void)
756 struct hist_browser
*self
= malloc(sizeof(*self
));
764 static void hist_browser__delete(struct hist_browser
*self
)
766 newtFormDestroy(self
->form
);
771 static int hist_browser__populate(struct hist_browser
*self
, struct hists
*hists
,
774 int max_len
= 0, idx
, cols
, rows
;
775 struct ui_progress
*progress
;
778 char seq
[] = ".", unit
;
780 unsigned long nr_events
= hists
->stats
.nr_events
[PERF_RECORD_SAMPLE
];
783 newtFormDestroy(self
->form
);
787 nr_events
= convert_unit(nr_events
, &unit
);
788 snprintf(str
, sizeof(str
), "Events: %lu%c ",
790 newtDrawRootText(0, 0, str
);
792 newtGetScreenSize(NULL
, &rows
);
794 if (symbol_conf
.use_callchain
)
795 self
->tree
= newtCheckboxTreeMulti(0, 0, rows
- 5, seq
,
798 self
->tree
= newtListbox(0, 0, rows
- 5,
800 NEWT_FLAG_RETURNEXIT
));
802 newtComponentAddCallback(self
->tree
, hist_browser__selection
,
805 progress
= ui_progress__new("Adding entries to the browser...",
807 if (progress
== NULL
)
811 for (nd
= rb_first(&hists
->entries
); nd
; nd
= rb_next(nd
)) {
812 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
818 len
= hist_entry__append_browser(h
, self
->tree
, hists
->stats
.total_period
);
821 if (symbol_conf
.use_callchain
)
822 hist_entry__append_callchain_browser(h
, self
->tree
,
823 hists
->stats
.total_period
, idx
++);
826 ui_progress__update(progress
, curr_hist
);
829 ui_progress__delete(progress
);
831 newtGetScreenSize(&cols
, &rows
);
836 if (!symbol_conf
.use_callchain
)
837 newtListboxSetWidth(self
->tree
, max_len
);
839 newtCenteredWindow(max_len
+ (symbol_conf
.use_callchain
? 5 : 0),
841 self
->form
= newt_form__new();
842 if (self
->form
== NULL
)
845 newtFormAddHotKey(self
->form
, 'A');
846 newtFormAddHotKey(self
->form
, 'a');
847 newtFormAddHotKey(self
->form
, 'D');
848 newtFormAddHotKey(self
->form
, 'd');
849 newtFormAddHotKey(self
->form
, 'T');
850 newtFormAddHotKey(self
->form
, 't');
851 newtFormAddHotKey(self
->form
, '?');
852 newtFormAddHotKey(self
->form
, 'H');
853 newtFormAddHotKey(self
->form
, 'h');
854 newtFormAddHotKey(self
->form
, NEWT_KEY_F1
);
855 newtFormAddHotKey(self
->form
, NEWT_KEY_RIGHT
);
856 newtFormAddHotKey(self
->form
, NEWT_KEY_TAB
);
857 newtFormAddHotKey(self
->form
, NEWT_KEY_UNTAB
);
858 newtFormAddComponents(self
->form
, self
->tree
, NULL
);
859 self
->selection
= newt__symbol_tree_get_current(self
->tree
);
864 static struct hist_entry
*hist_browser__selected_entry(struct hist_browser
*self
)
868 if (!symbol_conf
.use_callchain
)
871 indexes
= newtCheckboxTreeFindItem(self
->tree
, (void *)self
->selection
);
873 bool is_hist_entry
= indexes
[1] == NEWT_ARG_LAST
;
880 return container_of(self
->selection
, struct hist_entry
, ms
);
883 static struct thread
*hist_browser__selected_thread(struct hist_browser
*self
)
885 struct hist_entry
*he
= hist_browser__selected_entry(self
);
886 return he
? he
->thread
: NULL
;
889 static int hist_browser__title(char *bf
, size_t size
, const char *ev_name
,
890 const struct dso
*dso
, const struct thread
*thread
)
895 printed
+= snprintf(bf
+ printed
, size
- printed
,
897 (thread
->comm_set
? thread
->comm
: ""),
900 printed
+= snprintf(bf
+ printed
, size
- printed
,
901 "%sDSO: %s", thread
? " " : "",
903 return printed
?: snprintf(bf
, size
, "Event: %s", ev_name
);
906 int hists__browse(struct hists
*self
, const char *helpline
, const char *ev_name
)
908 struct hist_browser
*browser
= hist_browser__new();
909 struct pstack
*fstack
;
910 const struct thread
*thread_filter
= NULL
;
911 const struct dso
*dso_filter
= NULL
;
912 struct newtExitStruct es
;
919 fstack
= pstack__new(2);
923 ui_helpline__push(helpline
);
925 hist_browser__title(msg
, sizeof(msg
), ev_name
,
926 dso_filter
, thread_filter
);
927 if (hist_browser__populate(browser
, self
, msg
) < 0)
931 const struct thread
*thread
;
932 const struct dso
*dso
;
934 int nr_options
= 0, choice
= 0, i
,
935 annotate
= -2, zoom_dso
= -2, zoom_thread
= -2;
937 newtFormRun(browser
->form
, &es
);
939 thread
= hist_browser__selected_thread(browser
);
940 dso
= browser
->selection
->map
? browser
->selection
->map
->dso
: NULL
;
942 if (es
.reason
== NEWT_EXIT_HOTKEY
) {
951 * Exit the browser, let hists__browser_tree
952 * go to the next or previous
961 if (browser
->selection
->map
== NULL
&&
962 browser
->selection
->map
->dso
->annotate_warned
)
972 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
974 "a Annotate current symbol\n"
975 "h/?/F1 Show this window\n"
976 "d Zoom into current DSO\n"
977 "t Zoom into current Thread\n"
978 "q/CTRL+C Exit browser");
982 if (is_exit_key(key
)) {
983 if (key
== NEWT_KEY_ESCAPE
) {
984 if (dialog_yesno("Do you really want to exit?"))
992 if (es
.u
.key
== NEWT_KEY_LEFT
) {
995 if (pstack__empty(fstack
))
997 top
= pstack__pop(fstack
);
998 if (top
== &dso_filter
)
1000 if (top
== &thread_filter
)
1001 goto zoom_out_thread
;
1006 if (browser
->selection
->sym
!= NULL
&&
1007 !browser
->selection
->map
->dso
->annotate_warned
&&
1008 asprintf(&options
[nr_options
], "Annotate %s",
1009 browser
->selection
->sym
->name
) > 0)
1010 annotate
= nr_options
++;
1012 if (thread
!= NULL
&&
1013 asprintf(&options
[nr_options
], "Zoom %s %s(%d) thread",
1014 (thread_filter
? "out of" : "into"),
1015 (thread
->comm_set
? thread
->comm
: ""),
1017 zoom_thread
= nr_options
++;
1020 asprintf(&options
[nr_options
], "Zoom %s %s DSO",
1021 (dso_filter
? "out of" : "into"),
1022 (dso
->kernel
? "the Kernel" : dso
->short_name
)) > 0)
1023 zoom_dso
= nr_options
++;
1025 options
[nr_options
++] = (char *)"Exit";
1027 choice
= popup_menu(nr_options
, options
);
1029 for (i
= 0; i
< nr_options
- 1; ++i
)
1032 if (choice
== nr_options
- 1)
1038 if (choice
== annotate
) {
1039 struct hist_entry
*he
;
1041 if (browser
->selection
->map
->dso
->origin
== DSO__ORIG_KERNEL
) {
1042 browser
->selection
->map
->dso
->annotate_warned
= 1;
1043 ui_helpline__puts("No vmlinux file found, can't "
1044 "annotate with just a "
1049 he
= hist_browser__selected_entry(browser
);
1053 hist_entry__tui_annotate(he
);
1054 } else if (choice
== zoom_dso
) {
1057 pstack__remove(fstack
, &dso_filter
);
1064 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1065 dso
->kernel
? "the Kernel" : dso
->short_name
);
1067 pstack__push(fstack
, &dso_filter
);
1069 hists__filter_by_dso(self
, dso_filter
);
1070 hist_browser__title(msg
, sizeof(msg
), ev_name
,
1071 dso_filter
, thread_filter
);
1072 if (hist_browser__populate(browser
, self
, msg
) < 0)
1074 } else if (choice
== zoom_thread
) {
1076 if (thread_filter
) {
1077 pstack__remove(fstack
, &thread_filter
);
1080 thread_filter
= NULL
;
1082 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1083 thread
->comm_set
? thread
->comm
: "",
1085 thread_filter
= thread
;
1086 pstack__push(fstack
, &thread_filter
);
1088 hists__filter_by_thread(self
, thread_filter
);
1089 hist_browser__title(msg
, sizeof(msg
), ev_name
,
1090 dso_filter
, thread_filter
);
1091 if (hist_browser__populate(browser
, self
, msg
) < 0)
1096 pstack__delete(fstack
);
1098 hist_browser__delete(browser
);
1102 int hists__tui_browse_tree(struct rb_root
*self
, const char *help
)
1104 struct rb_node
*first
= rb_first(self
), *nd
= first
, *next
;
1108 struct hists
*hists
= rb_entry(nd
, struct hists
, rb_node
);
1109 const char *ev_name
= __event_name(hists
->type
, hists
->config
);
1111 key
= hists__browse(hists
, help
, ev_name
);
1113 if (is_exit_key(key
))
1122 case NEWT_KEY_UNTAB
:
1134 static struct newtPercentTreeColors
{
1135 const char *topColorFg
, *topColorBg
;
1136 const char *mediumColorFg
, *mediumColorBg
;
1137 const char *normalColorFg
, *normalColorBg
;
1138 const char *selColorFg
, *selColorBg
;
1139 const char *codeColorFg
, *codeColorBg
;
1140 } defaultPercentTreeColors
= {
1142 "green", "lightgray",
1143 "black", "lightgray",
1144 "lightgray", "magenta",
1145 "blue", "lightgray",
1148 void setup_browser(void)
1150 struct newtPercentTreeColors
*c
= &defaultPercentTreeColors
;
1152 if (!isatty(1) || !use_browser
|| dump_trace
) {
1161 ui_helpline__puts(" ");
1162 sltt_set_color(HE_COLORSET_TOP
, NULL
, c
->topColorFg
, c
->topColorBg
);
1163 sltt_set_color(HE_COLORSET_MEDIUM
, NULL
, c
->mediumColorFg
, c
->mediumColorBg
);
1164 sltt_set_color(HE_COLORSET_NORMAL
, NULL
, c
->normalColorFg
, c
->normalColorBg
);
1165 sltt_set_color(HE_COLORSET_SELECTED
, NULL
, c
->selColorFg
, c
->selColorBg
);
1166 sltt_set_color(HE_COLORSET_CODE
, NULL
, c
->codeColorFg
, c
->codeColorBg
);
1169 void exit_browser(bool wait_for_ok
)
1171 if (use_browser
> 0) {
1173 char title
[] = "Fatal Error", ok
[] = "Ok";
1174 newtWinMessage(title
, ok
, browser__last_msg
);