perf newt: Properly restore the screen when error exiting
[safe/jmp/linux-2.6] / tools / perf / util / newt.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #undef _GNU_SOURCE
4
5 #include <stdlib.h>
6 #include <newt.h>
7 #include <sys/ttydefaults.h>
8
9 #include "cache.h"
10 #include "hist.h"
11 #include "session.h"
12 #include "sort.h"
13 #include "symbol.h"
14
15 static void newt_form__set_exit_keys(newtComponent self)
16 {
17         newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
18         newtFormAddHotKey(self, 'Q');
19         newtFormAddHotKey(self, 'q');
20         newtFormAddHotKey(self, CTRL('c'));
21 }
22
23 static newtComponent newt_form__new(void)
24 {
25         newtComponent self = newtForm(NULL, NULL, 0);
26         if (self)
27                 newt_form__set_exit_keys(self);
28         return self;
29 }
30
31 static size_t hist_entry__append_browser(struct hist_entry *self,
32                                          newtComponent listbox, u64 total)
33 {
34         char bf[1024];
35         size_t len;
36         FILE *fp;
37
38         if (symbol_conf.exclude_other && !self->parent)
39                 return 0;
40
41         fp = fmemopen(bf, sizeof(bf), "w");
42         if (fp == NULL)
43                 return 0;
44
45         len = hist_entry__fprintf(self, NULL, false, 0, fp, total);
46
47         fclose(fp);
48         newtListboxAppendEntry(listbox, bf, self);
49         return len;
50 }
51
52 static void hist_entry__annotate_browser(struct hist_entry *self)
53 {
54         FILE *fp;
55         int cols, rows;
56         newtComponent form, listbox;
57         struct newtExitStruct es;
58         char *str;
59         size_t line_len, max_line_len = 0;
60         size_t max_usable_width;
61         char *line = NULL;
62
63         if (self->sym == NULL)
64                 return;
65
66         if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->sym->name) < 0)
67                 return;
68
69         fp = popen(str, "r");
70         if (fp == NULL)
71                 goto out_free_str;
72
73         newtPushHelpLine("Press ESC to exit");
74         newtGetScreenSize(&cols, &rows);
75         listbox = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
76
77         while (!feof(fp)) {
78                 if (getline(&line, &line_len, fp) < 0 || !line_len)
79                         break;
80                 while (line_len != 0 && isspace(line[line_len - 1]))
81                         line[--line_len] = '\0';
82
83                 if (line_len > max_line_len)
84                         max_line_len = line_len;
85                 newtListboxAppendEntry(listbox, line, NULL);
86         }
87         fclose(fp);
88         free(line);
89
90         max_usable_width = cols - 22;
91         if (max_line_len > max_usable_width)
92                 max_line_len = max_usable_width;
93
94         newtListboxSetWidth(listbox, max_line_len);
95
96         newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name);
97         form = newt_form__new();
98         newtFormAddComponents(form, listbox, NULL);
99
100         newtFormRun(form, &es);
101         newtFormDestroy(form);
102         newtPopWindow();
103         newtPopHelpLine();
104 out_free_str:
105         free(str);
106 }
107
108 void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
109                                 const char *helpline)
110 {
111         struct sort_entry *se;
112         struct rb_node *nd;
113         unsigned int width;
114         char *col_width = symbol_conf.col_width_list_str;
115         int rows;
116         size_t max_len = 0;
117         char str[1024];
118         newtComponent form, listbox;
119         struct newtExitStruct es;
120
121         snprintf(str, sizeof(str), "Samples: %Ld", session_total);
122         newtDrawRootText(0, 0, str);
123         newtPushHelpLine(helpline);
124
125         newtGetScreenSize(NULL, &rows);
126
127         form = newt_form__new();
128
129         listbox = newtListbox(1, 1, rows - 2, (NEWT_FLAG_SCROLL |
130                                                NEWT_FLAG_BORDER |
131                                                NEWT_FLAG_RETURNEXIT));
132
133         list_for_each_entry(se, &hist_entry__sort_list, list) {
134                 if (se->elide)
135                         continue;
136                 width = strlen(se->header);
137                 if (se->width) {
138                         if (symbol_conf.col_width_list_str) {
139                                 if (col_width) {
140                                         *se->width = atoi(col_width);
141                                         col_width = strchr(col_width, ',');
142                                         if (col_width)
143                                                 ++col_width;
144                                 }
145                         }
146                         *se->width = max(*se->width, width);
147                 }
148         }
149
150         for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
151                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
152                 size_t len = hist_entry__append_browser(h, listbox, session_total);
153                 if (len > max_len)
154                         max_len = len;
155         }
156
157         newtListboxSetWidth(listbox, max_len);
158         newtFormAddComponents(form, listbox, NULL);
159
160         while (1) {
161                 struct hist_entry *selection;
162
163                 newtFormRun(form, &es);
164                 if (es.reason == NEWT_EXIT_HOTKEY)
165                         break;
166                 selection = newtListboxGetCurrent(listbox);
167                 hist_entry__annotate_browser(selection);
168         }
169
170         newtFormDestroy(form);
171 }
172
173 static char browser__last_msg[1024];
174
175 int browser__show_help(const char *format, va_list ap)
176 {
177         int ret;
178         static int backlog;
179
180         ret = vsnprintf(browser__last_msg + backlog,
181                         sizeof(browser__last_msg) - backlog, format, ap);
182         backlog += ret;
183
184         if (browser__last_msg[backlog - 1] == '\n') {
185                 newtPopHelpLine();
186                 newtPushHelpLine(browser__last_msg);
187                 newtRefresh();
188                 backlog = 0;
189         }
190
191         return ret;
192 }
193
194 void setup_browser(void)
195 {
196         if (!isatty(1))
197                 return;
198
199         use_browser = true;
200         newtInit();
201         newtCls();
202         newtPushHelpLine(" ");
203 }
204
205 void exit_browser(bool wait_for_ok)
206 {
207         if (use_browser) {
208                 if (wait_for_ok) {
209                         char title[] = "Fatal Error", ok[] = "Ok";
210                         newtWinMessage(title, ok, browser__last_msg);
211                 }
212                 newtFinished();
213         }
214 }