gtkStatsChartMenu.cxx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file gtkStatsChartMenu.cxx
  10. * @author drose
  11. * @date 2006-01-16
  12. */
  13. #include "gtkStatsChartMenu.h"
  14. #include "gtkStatsMonitor.h"
  15. /**
  16. *
  17. */
  18. GtkStatsChartMenu::
  19. GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index) :
  20. _monitor(monitor),
  21. _thread_index(thread_index)
  22. {
  23. _menu = gtk_menu_new();
  24. gtk_widget_show(_menu);
  25. do_update();
  26. }
  27. /**
  28. *
  29. */
  30. GtkStatsChartMenu::
  31. ~GtkStatsChartMenu() {
  32. }
  33. /**
  34. * Returns the gtk widget for this particular menu.
  35. */
  36. GtkWidget *GtkStatsChartMenu::
  37. get_menu_widget() {
  38. return _menu;
  39. }
  40. /**
  41. * Adds the menu to the end of the indicated menu bar.
  42. */
  43. void GtkStatsChartMenu::
  44. add_to_menu_bar(GtkWidget *menu_bar, int position) {
  45. const PStatClientData *client_data = _monitor->get_client_data();
  46. std::string thread_name;
  47. if (_thread_index == 0) {
  48. // A special case for the main thread.
  49. thread_name = "Graphs";
  50. } else {
  51. thread_name = client_data->get_thread_name(_thread_index);
  52. }
  53. GtkWidget *menu_item = gtk_menu_item_new_with_label(thread_name.c_str());
  54. gtk_widget_show(menu_item);
  55. gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), _menu);
  56. gtk_menu_shell_insert(GTK_MENU_SHELL(menu_bar), menu_item, position);
  57. }
  58. /**
  59. * Checks to see if the menu needs to be updated (e.g. because of new data
  60. * from the client), and updates it if necessary.
  61. */
  62. void GtkStatsChartMenu::
  63. check_update() {
  64. PStatView &view = _monitor->get_view(_thread_index);
  65. if (view.get_level_index() != _last_level_index) {
  66. do_update();
  67. }
  68. }
  69. /**
  70. * Unconditionally updates the menu with the latest data from the client.
  71. */
  72. void GtkStatsChartMenu::
  73. do_update() {
  74. PStatView &view = _monitor->get_view(_thread_index);
  75. _last_level_index = view.get_level_index();
  76. // First, remove all of the old entries from the menu.
  77. gtk_container_foreach(GTK_CONTAINER(_menu), remove_menu_child, _menu);
  78. // Now rebuild the menu with the new set of entries.
  79. // The menu item(s) for the thread's frame time goes first.
  80. add_view(_menu, view.get_top_level(), false);
  81. bool needs_separator = true;
  82. // And then the menu item(s) for each of the level values.
  83. const PStatClientData *client_data = _monitor->get_client_data();
  84. int num_toplevel_collectors = client_data->get_num_toplevel_collectors();
  85. for (int tc = 0; tc < num_toplevel_collectors; tc++) {
  86. int collector = client_data->get_toplevel_collector(tc);
  87. if (client_data->has_collector(collector) &&
  88. client_data->get_collector_has_level(collector, _thread_index)) {
  89. // We put a separator between the above frame collector and the first
  90. // level collector.
  91. if (needs_separator) {
  92. GtkWidget *sep = gtk_separator_menu_item_new();
  93. gtk_widget_show(sep);
  94. gtk_menu_shell_append(GTK_MENU_SHELL(_menu), sep);
  95. needs_separator = false;
  96. }
  97. PStatView &level_view = _monitor->get_level_view(collector, _thread_index);
  98. add_view(_menu, level_view.get_top_level(), true);
  99. }
  100. }
  101. // Also menu items for flame graph and piano roll (following a separator).
  102. GtkWidget *sep = gtk_separator_menu_item_new();
  103. gtk_widget_show(sep);
  104. gtk_menu_shell_append(GTK_MENU_SHELL(_menu), sep);
  105. {
  106. GtkStatsMonitor::MenuDef smd(_thread_index, -2, false);
  107. const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
  108. GtkWidget *menu_item = gtk_menu_item_new_with_label("Flame Graph");
  109. gtk_widget_show(menu_item);
  110. gtk_menu_shell_append(GTK_MENU_SHELL(_menu), menu_item);
  111. g_signal_connect_swapped(G_OBJECT(menu_item), "activate",
  112. G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
  113. }
  114. {
  115. GtkStatsMonitor::MenuDef smd(_thread_index, -1, false);
  116. const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
  117. GtkWidget *menu_item = gtk_menu_item_new_with_label("Piano Roll");
  118. gtk_widget_show(menu_item);
  119. gtk_menu_shell_append(GTK_MENU_SHELL(_menu), menu_item);
  120. g_signal_connect_swapped(G_OBJECT(menu_item), "activate",
  121. G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
  122. }
  123. }
  124. /**
  125. * Adds a new entry or entries to the menu for the indicated view and its
  126. * children.
  127. */
  128. void GtkStatsChartMenu::
  129. add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level,
  130. bool show_level) {
  131. int collector = view_level->get_collector();
  132. const PStatClientData *client_data = _monitor->get_client_data();
  133. std::string collector_name = client_data->get_collector_name(collector);
  134. GtkStatsMonitor::MenuDef smd(_thread_index, collector, show_level);
  135. const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
  136. GtkWidget *menu_item = gtk_menu_item_new_with_label(collector_name.c_str());
  137. gtk_widget_show(menu_item);
  138. gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), menu_item);
  139. g_signal_connect_swapped(G_OBJECT(menu_item), "activate",
  140. G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
  141. int num_children = view_level->get_num_children();
  142. if (num_children > 1) {
  143. // If the collector has more than one child, add a menu entry to go
  144. // directly to each of its children.
  145. std::string submenu_name = collector_name + " components";
  146. GtkWidget *submenu_item = gtk_menu_item_new_with_label(submenu_name.c_str());
  147. gtk_widget_show(submenu_item);
  148. gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), submenu_item);
  149. GtkWidget *submenu = gtk_menu_new();
  150. gtk_widget_show(submenu);
  151. gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu_item), submenu);
  152. // Reverse the order since the menus are listed from the top down; we want
  153. // to be visually consistent with the graphs, which list these labels from
  154. // the bottom up.
  155. for (int c = num_children - 1; c >= 0; c--) {
  156. add_view(submenu, view_level->get_child(c), show_level);
  157. }
  158. }
  159. }
  160. /**
  161. * Callback when a menu item is selected.
  162. */
  163. void GtkStatsChartMenu::
  164. handle_menu(gpointer data) {
  165. const GtkStatsMonitor::MenuDef *menu_def = (GtkStatsMonitor::MenuDef *)data;
  166. GtkStatsMonitor *monitor = menu_def->_monitor;
  167. if (monitor == nullptr) {
  168. return;
  169. }
  170. if (menu_def->_collector_index == -2) {
  171. monitor->open_flame_graph(menu_def->_thread_index);
  172. }
  173. else if (menu_def->_collector_index < 0) {
  174. monitor->open_piano_roll(menu_def->_thread_index);
  175. }
  176. else {
  177. monitor->open_strip_chart(menu_def->_thread_index,
  178. menu_def->_collector_index,
  179. menu_def->_show_level);
  180. }
  181. }
  182. /**
  183. * Removes a previous menu child from the menu.
  184. */
  185. void GtkStatsChartMenu::
  186. remove_menu_child(GtkWidget *widget, gpointer data) {
  187. GtkWidget *menu = (GtkWidget *)data;
  188. gtk_container_remove(GTK_CONTAINER(menu), widget);
  189. }