]> Git Repo - linux.git/blob - tools/perf/ui/gtk/hists.c
Merge branch 'core-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / tools / perf / ui / gtk / hists.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "../evlist.h"
3 #include "../cache.h"
4 #include "../callchain.h"
5 #include "../evsel.h"
6 #include "../sort.h"
7 #include "../hist.h"
8 #include "../helpline.h"
9 #include "../string2.h"
10 #include "gtk.h"
11 #include <signal.h>
12
13 #define MAX_COLUMNS                     32
14
15 static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
16 {
17         int ret = 0;
18         int len;
19         va_list args;
20         double percent;
21         const char *markup;
22         char *buf = hpp->buf;
23         size_t size = hpp->size;
24
25         va_start(args, fmt);
26         len = va_arg(args, int);
27         percent = va_arg(args, double);
28         va_end(args);
29
30         markup = perf_gtk__get_percent_color(percent);
31         if (markup)
32                 ret += scnprintf(buf, size, markup);
33
34         ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
35
36         if (markup)
37                 ret += scnprintf(buf + ret, size - ret, "</span>");
38
39         return ret;
40 }
41
42 #define __HPP_COLOR_PERCENT_FN(_type, _field)                                   \
43 static u64 he_get_##_field(struct hist_entry *he)                               \
44 {                                                                               \
45         return he->stat._field;                                                 \
46 }                                                                               \
47                                                                                 \
48 static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,                \
49                                        struct perf_hpp *hpp,                    \
50                                        struct hist_entry *he)                   \
51 {                                                                               \
52         return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
53                         __percent_color_snprintf, true);                        \
54 }
55
56 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                               \
57 static u64 he_get_acc_##_field(struct hist_entry *he)                           \
58 {                                                                               \
59         return he->stat_acc->_field;                                            \
60 }                                                                               \
61                                                                                 \
62 static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,                \
63                                        struct perf_hpp *hpp,                    \
64                                        struct hist_entry *he)                   \
65 {                                                                               \
66         return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
67                             __percent_color_snprintf, true);                    \
68 }
69
70 __HPP_COLOR_PERCENT_FN(overhead, period)
71 __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
72 __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
73 __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
74 __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
75 __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
76
77 #undef __HPP_COLOR_PERCENT_FN
78
79
80 void perf_gtk__init_hpp(void)
81 {
82         perf_hpp__format[PERF_HPP__OVERHEAD].color =
83                                 perf_gtk__hpp_color_overhead;
84         perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
85                                 perf_gtk__hpp_color_overhead_sys;
86         perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
87                                 perf_gtk__hpp_color_overhead_us;
88         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
89                                 perf_gtk__hpp_color_overhead_guest_sys;
90         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
91                                 perf_gtk__hpp_color_overhead_guest_us;
92         perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
93                                 perf_gtk__hpp_color_overhead_acc;
94 }
95
96 static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
97                                          GtkTreeIter *parent, int col, u64 total)
98 {
99         struct rb_node *nd;
100         bool has_single_node = (rb_first(root) == rb_last(root));
101
102         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
103                 struct callchain_node *node;
104                 struct callchain_list *chain;
105                 GtkTreeIter iter, new_parent;
106                 bool need_new_parent;
107
108                 node = rb_entry(nd, struct callchain_node, rb_node);
109
110                 new_parent = *parent;
111                 need_new_parent = !has_single_node;
112
113                 callchain_node__make_parent_list(node);
114
115                 list_for_each_entry(chain, &node->parent_val, list) {
116                         char buf[128];
117
118                         gtk_tree_store_append(store, &iter, &new_parent);
119
120                         callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
121                         gtk_tree_store_set(store, &iter, 0, buf, -1);
122
123                         callchain_list__sym_name(chain, buf, sizeof(buf), false);
124                         gtk_tree_store_set(store, &iter, col, buf, -1);
125
126                         if (need_new_parent) {
127                                 /*
128                                  * Only show the top-most symbol in a callchain
129                                  * if it's not the only callchain.
130                                  */
131                                 new_parent = iter;
132                                 need_new_parent = false;
133                         }
134                 }
135
136                 list_for_each_entry(chain, &node->val, list) {
137                         char buf[128];
138
139                         gtk_tree_store_append(store, &iter, &new_parent);
140
141                         callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
142                         gtk_tree_store_set(store, &iter, 0, buf, -1);
143
144                         callchain_list__sym_name(chain, buf, sizeof(buf), false);
145                         gtk_tree_store_set(store, &iter, col, buf, -1);
146
147                         if (need_new_parent) {
148                                 /*
149                                  * Only show the top-most symbol in a callchain
150                                  * if it's not the only callchain.
151                                  */
152                                 new_parent = iter;
153                                 need_new_parent = false;
154                         }
155                 }
156         }
157 }
158
159 static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
160                                            GtkTreeIter *parent, int col, u64 total)
161 {
162         struct rb_node *nd;
163
164         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
165                 struct callchain_node *node;
166                 struct callchain_list *chain;
167                 GtkTreeIter iter;
168                 char buf[64];
169                 char *str, *str_alloc = NULL;
170                 bool first = true;
171
172                 node = rb_entry(nd, struct callchain_node, rb_node);
173
174                 callchain_node__make_parent_list(node);
175
176                 list_for_each_entry(chain, &node->parent_val, list) {
177                         char name[1024];
178
179                         callchain_list__sym_name(chain, name, sizeof(name), false);
180
181                         if (asprintf(&str, "%s%s%s",
182                                      first ? "" : str_alloc,
183                                      first ? "" : symbol_conf.field_sep ?: "; ",
184                                      name) < 0)
185                                 return;
186
187                         first = false;
188                         free(str_alloc);
189                         str_alloc = str;
190                 }
191
192                 list_for_each_entry(chain, &node->val, list) {
193                         char name[1024];
194
195                         callchain_list__sym_name(chain, name, sizeof(name), false);
196
197                         if (asprintf(&str, "%s%s%s",
198                                      first ? "" : str_alloc,
199                                      first ? "" : symbol_conf.field_sep ?: "; ",
200                                      name) < 0)
201                                 return;
202
203                         first = false;
204                         free(str_alloc);
205                         str_alloc = str;
206                 }
207
208                 gtk_tree_store_append(store, &iter, parent);
209
210                 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
211                 gtk_tree_store_set(store, &iter, 0, buf, -1);
212
213                 gtk_tree_store_set(store, &iter, col, str, -1);
214
215                 free(str_alloc);
216         }
217 }
218
219 static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
220                                           GtkTreeIter *parent, int col, u64 total)
221 {
222         struct rb_node *nd;
223         bool has_single_node = (rb_first(root) == rb_last(root));
224
225         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
226                 struct callchain_node *node;
227                 struct callchain_list *chain;
228                 GtkTreeIter iter, new_parent;
229                 bool need_new_parent;
230                 u64 child_total;
231
232                 node = rb_entry(nd, struct callchain_node, rb_node);
233
234                 new_parent = *parent;
235                 need_new_parent = !has_single_node && (node->val_nr > 1);
236
237                 list_for_each_entry(chain, &node->val, list) {
238                         char buf[128];
239
240                         gtk_tree_store_append(store, &iter, &new_parent);
241
242                         callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
243                         gtk_tree_store_set(store, &iter, 0, buf, -1);
244
245                         callchain_list__sym_name(chain, buf, sizeof(buf), false);
246                         gtk_tree_store_set(store, &iter, col, buf, -1);
247
248                         if (need_new_parent) {
249                                 /*
250                                  * Only show the top-most symbol in a callchain
251                                  * if it's not the only callchain.
252                                  */
253                                 new_parent = iter;
254                                 need_new_parent = false;
255                         }
256                 }
257
258                 if (callchain_param.mode == CHAIN_GRAPH_REL)
259                         child_total = node->children_hit;
260                 else
261                         child_total = total;
262
263                 /* Now 'iter' contains info of the last callchain_list */
264                 perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
265                                               child_total);
266         }
267 }
268
269 static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
270                                     GtkTreeIter *parent, int col, u64 total)
271 {
272         if (callchain_param.mode == CHAIN_FLAT)
273                 perf_gtk__add_callchain_flat(root, store, parent, col, total);
274         else if (callchain_param.mode == CHAIN_FOLDED)
275                 perf_gtk__add_callchain_folded(root, store, parent, col, total);
276         else
277                 perf_gtk__add_callchain_graph(root, store, parent, col, total);
278 }
279
280 static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
281                              GtkTreeViewColumn *col __maybe_unused,
282                              gpointer user_data __maybe_unused)
283 {
284         bool expanded = gtk_tree_view_row_expanded(view, path);
285
286         if (expanded)
287                 gtk_tree_view_collapse_row(view, path);
288         else
289                 gtk_tree_view_expand_row(view, path, FALSE);
290 }
291
292 static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
293                                  float min_pcnt)
294 {
295         struct perf_hpp_fmt *fmt;
296         GType col_types[MAX_COLUMNS];
297         GtkCellRenderer *renderer;
298         GtkTreeStore *store;
299         struct rb_node *nd;
300         GtkWidget *view;
301         int col_idx;
302         int sym_col = -1;
303         int nr_cols;
304         char s[512];
305
306         struct perf_hpp hpp = {
307                 .buf            = s,
308                 .size           = sizeof(s),
309         };
310
311         nr_cols = 0;
312
313         hists__for_each_format(hists, fmt)
314                 col_types[nr_cols++] = G_TYPE_STRING;
315
316         store = gtk_tree_store_newv(nr_cols, col_types);
317
318         view = gtk_tree_view_new();
319
320         renderer = gtk_cell_renderer_text_new();
321
322         col_idx = 0;
323
324         hists__for_each_format(hists, fmt) {
325                 if (perf_hpp__should_skip(fmt, hists))
326                         continue;
327
328                 /*
329                  * XXX no way to determine where symcol column is..
330                  *     Just use last column for now.
331                  */
332                 if (perf_hpp__is_sort_entry(fmt))
333                         sym_col = col_idx;
334
335                 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
336                                                             -1, fmt->name,
337                                                             renderer, "markup",
338                                                             col_idx++, NULL);
339         }
340
341         for (col_idx = 0; col_idx < nr_cols; col_idx++) {
342                 GtkTreeViewColumn *column;
343
344                 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
345                 gtk_tree_view_column_set_resizable(column, TRUE);
346
347                 if (col_idx == sym_col) {
348                         gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
349                                                           column);
350                 }
351         }
352
353         gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
354
355         g_object_unref(GTK_TREE_MODEL(store));
356
357         for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
358                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
359                 GtkTreeIter iter;
360                 u64 total = hists__total_period(h->hists);
361                 float percent;
362
363                 if (h->filtered)
364                         continue;
365
366                 percent = hist_entry__get_percent_limit(h);
367                 if (percent < min_pcnt)
368                         continue;
369
370                 gtk_tree_store_append(store, &iter, NULL);
371
372                 col_idx = 0;
373
374                 hists__for_each_format(hists, fmt) {
375                         if (perf_hpp__should_skip(fmt, h->hists))
376                                 continue;
377
378                         if (fmt->color)
379                                 fmt->color(fmt, &hpp, h);
380                         else
381                                 fmt->entry(fmt, &hpp, h);
382
383                         gtk_tree_store_set(store, &iter, col_idx++, s, -1);
384                 }
385
386                 if (hist_entry__has_callchains(h) &&
387                     symbol_conf.use_callchain && hists__has(hists, sym)) {
388                         if (callchain_param.mode == CHAIN_GRAPH_REL)
389                                 total = symbol_conf.cumulate_callchain ?
390                                         h->stat_acc->period : h->stat.period;
391
392                         perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
393                                                 sym_col, total);
394                 }
395         }
396
397         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
398
399         g_signal_connect(view, "row-activated",
400                          G_CALLBACK(on_row_activated), NULL);
401         gtk_container_add(GTK_CONTAINER(window), view);
402 }
403
404 static void perf_gtk__add_hierarchy_entries(struct hists *hists,
405                                             struct rb_root_cached *root,
406                                             GtkTreeStore *store,
407                                             GtkTreeIter *parent,
408                                             struct perf_hpp *hpp,
409                                             float min_pcnt)
410 {
411         int col_idx = 0;
412         struct rb_node *node;
413         struct hist_entry *he;
414         struct perf_hpp_fmt *fmt;
415         struct perf_hpp_list_node *fmt_node;
416         u64 total = hists__total_period(hists);
417         int size;
418
419         for (node = rb_first_cached(root); node; node = rb_next(node)) {
420                 GtkTreeIter iter;
421                 float percent;
422                 char *bf;
423
424                 he = rb_entry(node, struct hist_entry, rb_node);
425                 if (he->filtered)
426                         continue;
427
428                 percent = hist_entry__get_percent_limit(he);
429                 if (percent < min_pcnt)
430                         continue;
431
432                 gtk_tree_store_append(store, &iter, parent);
433
434                 col_idx = 0;
435
436                 /* the first hpp_list_node is for overhead columns */
437                 fmt_node = list_first_entry(&hists->hpp_formats,
438                                             struct perf_hpp_list_node, list);
439                 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
440                         if (fmt->color)
441                                 fmt->color(fmt, hpp, he);
442                         else
443                                 fmt->entry(fmt, hpp, he);
444
445                         gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
446                 }
447
448                 bf = hpp->buf;
449                 size = hpp->size;
450                 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
451                         int ret;
452
453                         if (fmt->color)
454                                 ret = fmt->color(fmt, hpp, he);
455                         else
456                                 ret = fmt->entry(fmt, hpp, he);
457
458                         snprintf(hpp->buf + ret, hpp->size - ret, "  ");
459                         advance_hpp(hpp, ret + 2);
460                 }
461
462                 gtk_tree_store_set(store, &iter, col_idx, ltrim(rtrim(bf)), -1);
463
464                 if (!he->leaf) {
465                         hpp->buf = bf;
466                         hpp->size = size;
467
468                         perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
469                                                         store, &iter, hpp,
470                                                         min_pcnt);
471
472                         if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
473                                 char buf[32];
474                                 GtkTreeIter child;
475
476                                 snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
477                                          min_pcnt);
478
479                                 gtk_tree_store_append(store, &child, &iter);
480                                 gtk_tree_store_set(store, &child, col_idx, buf, -1);
481                         }
482                 }
483
484                 if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
485                         if (callchain_param.mode == CHAIN_GRAPH_REL)
486                                 total = symbol_conf.cumulate_callchain ?
487                                         he->stat_acc->period : he->stat.period;
488
489                         perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
490                                                 col_idx, total);
491                 }
492         }
493
494 }
495
496 static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
497                                      float min_pcnt)
498 {
499         struct perf_hpp_fmt *fmt;
500         struct perf_hpp_list_node *fmt_node;
501         GType col_types[MAX_COLUMNS];
502         GtkCellRenderer *renderer;
503         GtkTreeStore *store;
504         GtkWidget *view;
505         int col_idx;
506         int nr_cols = 0;
507         char s[512];
508         char buf[512];
509         bool first_node, first_col;
510         struct perf_hpp hpp = {
511                 .buf            = s,
512                 .size           = sizeof(s),
513         };
514
515         hists__for_each_format(hists, fmt) {
516                 if (perf_hpp__is_sort_entry(fmt) ||
517                     perf_hpp__is_dynamic_entry(fmt))
518                         break;
519
520                 col_types[nr_cols++] = G_TYPE_STRING;
521         }
522         col_types[nr_cols++] = G_TYPE_STRING;
523
524         store = gtk_tree_store_newv(nr_cols, col_types);
525         view = gtk_tree_view_new();
526         renderer = gtk_cell_renderer_text_new();
527
528         col_idx = 0;
529
530         /* the first hpp_list_node is for overhead columns */
531         fmt_node = list_first_entry(&hists->hpp_formats,
532                                     struct perf_hpp_list_node, list);
533         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
534                 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
535                                                             -1, fmt->name,
536                                                             renderer, "markup",
537                                                             col_idx++, NULL);
538         }
539
540         /* construct merged column header since sort keys share single column */
541         buf[0] = '\0';
542         first_node = true;
543         list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
544                 if (!first_node)
545                         strcat(buf, " / ");
546                 first_node = false;
547
548                 first_col = true;
549                 perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
550                         if (perf_hpp__should_skip(fmt, hists))
551                                 continue;
552
553                         if (!first_col)
554                                 strcat(buf, "+");
555                         first_col = false;
556
557                         fmt->header(fmt, &hpp, hists, 0, NULL);
558                         strcat(buf, ltrim(rtrim(hpp.buf)));
559                 }
560         }
561
562         gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
563                                                     -1, buf,
564                                                     renderer, "markup",
565                                                     col_idx++, NULL);
566
567         for (col_idx = 0; col_idx < nr_cols; col_idx++) {
568                 GtkTreeViewColumn *column;
569
570                 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
571                 gtk_tree_view_column_set_resizable(column, TRUE);
572
573                 if (col_idx == 0) {
574                         gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
575                                                           column);
576                 }
577         }
578
579         gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
580         g_object_unref(GTK_TREE_MODEL(store));
581
582         perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
583                                         NULL, &hpp, min_pcnt);
584
585         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
586
587         g_signal_connect(view, "row-activated",
588                          G_CALLBACK(on_row_activated), NULL);
589         gtk_container_add(GTK_CONTAINER(window), view);
590 }
591
592 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
593                                   const char *help,
594                                   struct hist_browser_timer *hbt __maybe_unused,
595                                   float min_pcnt)
596 {
597         struct perf_evsel *pos;
598         GtkWidget *vbox;
599         GtkWidget *notebook;
600         GtkWidget *info_bar;
601         GtkWidget *statbar;
602         GtkWidget *window;
603
604         signal(SIGSEGV, perf_gtk__signal);
605         signal(SIGFPE,  perf_gtk__signal);
606         signal(SIGINT,  perf_gtk__signal);
607         signal(SIGQUIT, perf_gtk__signal);
608         signal(SIGTERM, perf_gtk__signal);
609
610         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
611
612         gtk_window_set_title(GTK_WINDOW(window), "perf report");
613
614         g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
615
616         pgctx = perf_gtk__activate_context(window);
617         if (!pgctx)
618                 return -1;
619
620         vbox = gtk_vbox_new(FALSE, 0);
621
622         notebook = gtk_notebook_new();
623
624         gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
625
626         info_bar = perf_gtk__setup_info_bar();
627         if (info_bar)
628                 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
629
630         statbar = perf_gtk__setup_statusbar();
631         gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
632
633         gtk_container_add(GTK_CONTAINER(window), vbox);
634
635         evlist__for_each_entry(evlist, pos) {
636                 struct hists *hists = evsel__hists(pos);
637                 const char *evname = perf_evsel__name(pos);
638                 GtkWidget *scrolled_window;
639                 GtkWidget *tab_label;
640                 char buf[512];
641                 size_t size = sizeof(buf);
642
643                 if (symbol_conf.event_group) {
644                         if (!perf_evsel__is_group_leader(pos))
645                                 continue;
646
647                         if (pos->nr_members > 1) {
648                                 perf_evsel__group_desc(pos, buf, size);
649                                 evname = buf;
650                         }
651                 }
652
653                 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
654
655                 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
656                                                         GTK_POLICY_AUTOMATIC,
657                                                         GTK_POLICY_AUTOMATIC);
658
659                 if (symbol_conf.report_hierarchy)
660                         perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
661                 else
662                         perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
663
664                 tab_label = gtk_label_new(evname);
665
666                 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
667         }
668
669         gtk_widget_show_all(window);
670
671         perf_gtk__resize_window(window);
672
673         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
674
675         ui_helpline__push(help);
676
677         gtk_main();
678
679         perf_gtk__deactivate_context(&pgctx);
680
681         return 0;
682 }
This page took 0.071319 seconds and 4 git commands to generate.