| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850 |
- /**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University. All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license. You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file gtkStatsMonitor.cxx
- * @author drose
- * @date 2006-01-16
- */
- #include "gtkStatsMonitor.h"
- #include "gtkStats.h"
- #include "gtkStatsServer.h"
- #include "gtkStatsStripChart.h"
- #include "gtkStatsChartMenu.h"
- #include "gtkStatsPianoRoll.h"
- #include "gtkStatsFlameGraph.h"
- #include "gtkStatsTimeline.h"
- #include "pStatGraph.h"
- #include "pStatCollectorDef.h"
- #include "convert_srgb.h"
- /**
- *
- */
- GtkStatsMonitor::
- GtkStatsMonitor(GtkStatsServer *server) : PStatMonitor(server) {
- _window = server->get_window();
- _menu_bar = server->get_menu_bar();
- _status_bar = server->get_status_bar();
- // These will be filled in later when the menu is created.
- _scroll_speed = 0.0;
- _pause = false;
- _next_chart_index = 2;
- _resolution = gdk_screen_get_resolution(gdk_screen_get_default());
- setup_speed_menu();
- setup_frame_rate_label();
- }
- /**
- *
- */
- GtkStatsMonitor::
- ~GtkStatsMonitor() {
- close();
- }
- /**
- * Closes all the graphs associated with this monitor.
- */
- void GtkStatsMonitor::
- close() {
- PStatMonitor::close();
- remove_all_graphs();
- for (GtkWidget *label : _status_bar_labels) {
- gtk_container_remove(GTK_CONTAINER(_status_bar), label);
- }
- _status_bar_collectors.clear();
- _status_bar_labels.clear();
- if (_speed_menu_item != nullptr) {
- gtk_container_remove(GTK_CONTAINER(_menu_bar), _speed_menu_item);
- _speed_menu_item = nullptr;
- }
- for (GtkStatsChartMenu *chart_menu : _chart_menus) {
- chart_menu->remove_from_menu_bar(_menu_bar);
- delete chart_menu;
- }
- _chart_menus.clear();
- if (_frame_rate_menu_item != nullptr) {
- gtk_container_remove(GTK_CONTAINER(_menu_bar), _frame_rate_menu_item);
- _frame_rate_menu_item = nullptr;
- }
- _next_chart_index = 2;
- }
- /**
- * Should be redefined to return a descriptive name for the type of
- * PStatsMonitor this is.
- */
- std::string GtkStatsMonitor::
- get_monitor_name() {
- return "GtkStats";
- }
- /**
- * Called after the monitor has been fully set up. At this time, it will have
- * a valid _client_data pointer, and things like is_alive() and close() will
- * be meaningful. However, we may not yet know who we're connected to
- * (is_client_known() may return false), and we may not know anything about
- * the threads or collectors we're about to get data on.
- */
- void GtkStatsMonitor::
- initialized() {
- }
- /**
- * Called when the "hello" message has been received from the client. At this
- * time, the client's hostname and program name will be known.
- */
- void GtkStatsMonitor::
- got_hello() {
- }
- /**
- * Like got_hello(), this is called when the "hello" message has been received
- * from the client. At this time, the client's hostname and program name will
- * be known. However, the client appears to be an incompatible version and
- * the connection will be terminated; the monitor should issue a message to
- * that effect.
- */
- void GtkStatsMonitor::
- got_bad_version(int client_major, int client_minor,
- int server_major, int server_minor) {
- std::ostringstream str;
- str << "Unable to honor connection attempt from "
- << get_client_progname() << " on " << get_client_hostname()
- << ": unsupported PStats version "
- << client_major << "." << client_minor;
- if (server_minor == 0) {
- str << " (server understands version " << server_major
- << "." << server_minor << " only).";
- } else {
- str << " (server understands versions " << server_major
- << ".0 through " << server_major << "." << server_minor << ").";
- }
- std::string message = str.str();
- GtkWidget *dialog =
- gtk_message_dialog_new(GTK_WINDOW(_window),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- "%s", message.c_str());
- gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
- }
- /**
- * Called whenever a new Collector definition is received from the client.
- * Generally, the client will send all of its collectors over shortly after
- * connecting, but there's no guarantee that they will all be received before
- * the first frames are received. The monitor should be prepared to accept
- * new Collector definitions midstream.
- */
- void GtkStatsMonitor::
- new_collector(int collector_index) {
- for (GtkStatsGraph *graph : _graphs) {
- graph->new_collector(collector_index);
- }
- // We might need to update our menus.
- for (GtkStatsChartMenu *chart_menu : _chart_menus) {
- chart_menu->check_update();
- }
- }
- /**
- * Called whenever a new Thread definition is received from the client.
- * Generally, the client will send all of its threads over shortly after
- * connecting, but there's no guarantee that they will all be received before
- * the first frames are received. The monitor should be prepared to accept
- * new Thread definitions midstream.
- */
- void GtkStatsMonitor::
- new_thread(int thread_index) {
- GtkStatsChartMenu *chart_menu = new GtkStatsChartMenu(this, thread_index);
- chart_menu->add_to_menu_bar(_menu_bar, _next_chart_index);
- ++_next_chart_index;
- _chart_menus.push_back(chart_menu);
- }
- /**
- * Called as each frame's data is made available. There is no guarantee the
- * frames will arrive in order, or that all of them will arrive at all. The
- * monitor should be prepared to accept frames received out-of-order or
- * missing.
- */
- void GtkStatsMonitor::
- new_data(int thread_index, int frame_number) {
- for (GtkStatsGraph *graph : _graphs) {
- graph->new_data(thread_index, frame_number);
- }
- if (thread_index == 0) {
- update_status_bar();
- }
- if (!_have_data) {
- open_default_graphs();
- _have_data = true;
- // Flash the window.
- gtk_window_set_urgency_hint(GTK_WINDOW(_window), TRUE);
- }
- }
- /**
- * Called whenever the connection to the client has been lost. This is a
- * permanent state change. The monitor should update its display to represent
- * this, and may choose to close down automatically.
- */
- void GtkStatsMonitor::
- lost_connection() {
- nout << "Lost connection to " << get_client_hostname() << "\n";
- }
- /**
- * If has_idle() returns true, this will be called periodically to allow the
- * monitor to update its display or whatever it needs to do.
- */
- void GtkStatsMonitor::
- idle() {
- // Check if any of our chart menus need updating.
- for (GtkStatsChartMenu *chart_menu : _chart_menus) {
- chart_menu->check_update();
- }
- // Update the frame rate label from the main thread (thread 0).
- const PStatThreadData *thread_data = get_client_data()->get_thread_data(0);
- double frame_rate = thread_data->get_frame_rate();
- if (frame_rate != 0.0f) {
- char buffer[128];
- sprintf(buffer, "%0.1f ms / %0.1f Hz", 1000.0f / frame_rate, frame_rate);
- gtk_label_set_text(GTK_LABEL(_frame_rate_label), buffer);
- if (!_status_bar_labels.empty()) {
- gtk_label_set_text(GTK_LABEL(_status_bar_labels[0]), buffer);
- }
- }
- }
- /**
- * Should be redefined to return true if you want to redefine idle() and
- * expect it to be called.
- */
- bool GtkStatsMonitor::
- has_idle() {
- return true;
- }
- /**
- * Called when the user guide bars have been changed.
- */
- void GtkStatsMonitor::
- user_guide_bars_changed() {
- for (GtkStatsGraph *graph : _graphs) {
- graph->user_guide_bars_changed();
- }
- }
- /**
- * Returns the window handle to the monitor's window.
- */
- GtkWidget *GtkStatsMonitor::
- get_window() const {
- return _window;
- }
- /**
- *
- */
- GtkAccelGroup *GtkStatsMonitor::
- get_accel_group() const {
- return ((GtkStatsServer *)_server)->get_accel_group();
- }
- /**
- * Returns the screen DPI.
- */
- double GtkStatsMonitor::
- get_resolution() const {
- return _resolution;
- }
- /**
- * Opens a new timeline.
- */
- PStatGraph *GtkStatsMonitor::
- open_timeline() {
- GtkStatsTimeline *graph = new GtkStatsTimeline(this);
- add_graph(graph);
- return graph;
- }
- /**
- * Opens a new flame graph showing the indicated data.
- */
- PStatGraph *GtkStatsMonitor::
- open_flame_graph(int thread_index, int collector_index) {
- GtkStatsFlameGraph *graph = new GtkStatsFlameGraph(this, thread_index, collector_index);
- add_graph(graph);
- return graph;
- }
- /**
- * Opens a new strip chart showing the indicated data.
- */
- PStatGraph *GtkStatsMonitor::
- open_strip_chart(int thread_index, int collector_index, bool show_level) {
- GtkStatsStripChart *graph =
- new GtkStatsStripChart(this, thread_index, collector_index, show_level);
- add_graph(graph);
- return graph;
- }
- /**
- * Opens a new piano roll showing the indicated data.
- */
- PStatGraph *GtkStatsMonitor::
- open_piano_roll(int thread_index) {
- GtkStatsPianoRoll *graph = new GtkStatsPianoRoll(this, thread_index);
- add_graph(graph);
- return graph;
- }
- /**
- * Opens a dialog to change the given collector color.
- */
- void GtkStatsMonitor::
- choose_collector_color(int collector_index) {
- const LRGBColor ¤t = get_collector_color(collector_index);
- GtkWidget *chooser = gtk_color_chooser_dialog_new(nullptr, GTK_WINDOW(_window));
- gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(chooser), FALSE);
- GdkRGBA rgba;
- rgba.red = encode_sRGB_float((float)current[0]);
- rgba.green = encode_sRGB_float((float)current[1]);
- rgba.blue = encode_sRGB_float((float)current[2]);
- rgba.alpha = 1.0;
- gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(chooser), &rgba);
- if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
- gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(chooser), &rgba);
- LRGBColor result(
- decode_sRGB_float((float)rgba.red),
- decode_sRGB_float((float)rgba.green),
- decode_sRGB_float((float)rgba.blue));
- set_collector_color(collector_index, result);
- for (GtkStatsGraph *graph : _graphs) {
- graph->reset_collector_color(collector_index);
- }
- }
- gtk_widget_destroy(chooser);
- }
- /**
- * Resets the color of the given collector to the default.
- */
- void GtkStatsMonitor::
- reset_collector_color(int collector_index) {
- clear_collector_color(collector_index);
- for (GtkStatsGraph *graph : _graphs) {
- graph->reset_collector_color(collector_index);
- }
- }
- /**
- * Adds a new MenuDef to the monitor, or returns an existing one if there is
- * already one just like it.
- */
- const GtkStatsMonitor::MenuDef *GtkStatsMonitor::
- add_menu(const MenuDef &menu_def) {
- std::pair<Menus::iterator, bool> result = _menus.insert(menu_def);
- Menus::iterator mi = result.first;
- const GtkStatsMonitor::MenuDef &new_menu_def = (*mi);
- if (result.second) {
- // A new MenuDef was inserted.
- ((GtkStatsMonitor::MenuDef &)new_menu_def)._monitor = this;
- }
- return &new_menu_def;
- }
- /**
- * Called when the user selects a new time units from the monitor pulldown
- * menu, this should adjust the units for all graphs to the indicated mask if
- * it is a time-based graph.
- */
- void GtkStatsMonitor::
- set_time_units(int unit_mask) {
- for (GtkStatsGraph *graph : _graphs) {
- graph->set_time_units(unit_mask);
- }
- }
- /**
- * Called when the user selects a new scroll speed from the monitor pulldown
- * menu, this should adjust the speeds for all graphs to the indicated value.
- */
- void GtkStatsMonitor::
- set_scroll_speed(double scroll_speed) {
- _scroll_speed = scroll_speed;
- // First, change all of the open graphs appropriately.
- for (GtkStatsGraph *graph : _graphs) {
- graph->set_scroll_speed(_scroll_speed);
- }
- }
- /**
- * Called when the user selects a pause on or pause off option from the menu.
- */
- void GtkStatsMonitor::
- set_pause(bool pause) {
- _pause = pause;
- // First, change all of the open graphs appropriately.
- for (GtkStatsGraph *graph : _graphs) {
- graph->set_pause(_pause);
- }
- }
- /**
- * Adds the newly-created graph to the list of managed graphs.
- */
- void GtkStatsMonitor::
- add_graph(GtkStatsGraph *graph) {
- _graphs.insert(graph);
- graph->set_time_units(((GtkStatsServer *)_server)->get_time_units());
- graph->set_scroll_speed(_scroll_speed);
- graph->set_pause(_pause);
- }
- /**
- * Deletes the indicated graph.
- */
- void GtkStatsMonitor::
- remove_graph(GtkStatsGraph *graph) {
- Graphs::iterator gi = _graphs.find(graph);
- if (gi != _graphs.end()) {
- _graphs.erase(gi);
- delete graph;
- }
- }
- /**
- * Deletes all open graphs.
- */
- void GtkStatsMonitor::
- remove_all_graphs() {
- for (GtkStatsGraph *graph : _graphs) {
- delete graph;
- }
- _graphs.clear();
- }
- /**
- * Creates the "Speed" pulldown menu.
- */
- void GtkStatsMonitor::
- setup_speed_menu() {
- GtkWidget *menu = gtk_menu_new();
- _speed_menu_item = gtk_menu_item_new_with_label("Speed");
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(_speed_menu_item), menu);
- gtk_menu_shell_append(GTK_MENU_SHELL(_menu_bar), _speed_menu_item);
- GSList *group = nullptr;
- GtkWidget *item;
- item = gtk_radio_menu_item_new_with_label(group, "1");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "toggled",
- G_CALLBACK(+[](GtkMenuItem *item, gpointer data) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))) {
- GtkStatsMonitor *self = (GtkStatsMonitor *)data;
- self->set_scroll_speed(1);
- }
- }), this);
- group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
- item = gtk_radio_menu_item_new_with_label(group, "2");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "toggled",
- G_CALLBACK(+[](GtkMenuItem *item, gpointer data) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))) {
- GtkStatsMonitor *self = (GtkStatsMonitor *)data;
- self->set_scroll_speed(2);
- }
- }), this);
- group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
- item = gtk_radio_menu_item_new_with_label(group, "3");
- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "toggled",
- G_CALLBACK(+[](GtkMenuItem *item, gpointer data) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))) {
- GtkStatsMonitor *self = (GtkStatsMonitor *)data;
- self->set_scroll_speed(3);
- }
- }), this);
- group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
- item = gtk_radio_menu_item_new_with_label(group, "6");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "toggled",
- G_CALLBACK(+[](GtkMenuItem *item, gpointer data) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))) {
- GtkStatsMonitor *self = (GtkStatsMonitor *)data;
- self->set_scroll_speed(6);
- }
- }), this);
- group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
- item = gtk_radio_menu_item_new_with_label(group, "12");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "toggled",
- G_CALLBACK(+[](GtkMenuItem *item, gpointer data) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))) {
- GtkStatsMonitor *self = (GtkStatsMonitor *)data;
- self->set_scroll_speed(12);
- }
- }), this);
- group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
- item = gtk_separator_menu_item_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- item = gtk_check_menu_item_new_with_label("pause");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "toggled",
- G_CALLBACK(+[](GtkMenuItem *item, gpointer data) {
- GtkStatsMonitor *self = (GtkStatsMonitor *)data;
- self->set_pause(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
- }), this);
- set_scroll_speed(3);
- set_pause(false);
- gtk_widget_show_all(_speed_menu_item);
- ++_next_chart_index;
- }
- /**
- * Creates the frame rate label on the right end of the menu bar. This is
- * used as a text label to display the main thread's frame rate to the user,
- * although it is implemented as a right-justified toplevel menu item that
- * doesn't open to anything.
- */
- void GtkStatsMonitor::
- setup_frame_rate_label() {
- _frame_rate_menu_item = gtk_menu_item_new();
- _frame_rate_label = gtk_label_new("");
- gtk_container_add(GTK_CONTAINER(_frame_rate_menu_item), _frame_rate_label);
- gtk_widget_set_sensitive(_frame_rate_menu_item, FALSE);
- gtk_widget_show(_frame_rate_menu_item);
- gtk_widget_show(_frame_rate_label);
- gtk_menu_item_set_right_justified(GTK_MENU_ITEM(_frame_rate_menu_item), TRUE);
- gtk_menu_shell_append(GTK_MENU_SHELL(_menu_bar), _frame_rate_menu_item);
- }
- /**
- * Updates the status bar.
- */
- void GtkStatsMonitor::
- update_status_bar() {
- const PStatClientData *client_data = get_client_data();
- if (client_data == nullptr) {
- return;
- }
- const PStatThreadData *thread_data = get_client_data()->get_thread_data(0);
- if (thread_data == nullptr || thread_data->is_empty()) {
- return;
- }
- int frame_number = thread_data->get_latest_frame_number();
- const PStatFrameData &frame_data = thread_data->get_latest_frame();
- pvector<int> collectors;
- // The first label displays the frame rate.
- size_t li = 1;
- collectors.push_back(0);
- if (_status_bar_labels.empty()) {
- GtkWidget *label = gtk_label_new("");
- gtk_container_add(GTK_CONTAINER(_status_bar), label);
- _status_bar_labels.push_back(label);
- }
- // Gather the top-level collector list.
- int num_toplevel_collectors = client_data->get_num_toplevel_collectors();
- for (int tc = 0; tc < num_toplevel_collectors; tc++) {
- int collector = client_data->get_toplevel_collector(tc);
- if (client_data->has_collector(collector) &&
- client_data->get_collector_has_level(collector, 0)) {
- PStatView &view = get_level_view(collector, 0);
- view.set_to_frame(frame_data);
- double value = view.get_net_value();
- if (value == 0.0) {
- // Don't include it unless we've included it before.
- if (std::find(_status_bar_collectors.begin(), _status_bar_collectors.end(), collector) == _status_bar_collectors.end()) {
- continue;
- }
- }
- // Add the value for other threads that have this collector.
- for (int thread_index = 1; thread_index < client_data->get_num_threads(); ++thread_index) {
- PStatView &view = get_level_view(collector, thread_index);
- view.set_to_frame(frame_number);
- value += view.get_net_value();
- }
- const PStatCollectorDef &def = client_data->get_collector_def(collector);
- std::string text = def._name;
- text += ": " + PStatGraph::format_number(value, PStatGraph::GBU_named | PStatGraph::GBU_show_units, def._level_units);
- GtkWidget *label;
- if (li < _status_bar_labels.size()) {
- label = _status_bar_labels[li++];
- gtk_label_set_text(GTK_LABEL(label), text.c_str());
- }
- else {
- label = gtk_label_new(text.c_str());
- gtk_container_add(GTK_CONTAINER(_status_bar), label);
- _status_bar_labels.push_back(label);
- }
- collectors.push_back(collector);
- }
- }
- _status_bar_collectors = std::move(collectors);
- gtk_widget_show_all(_status_bar);
- }
- /**
- * Handles clicks on a partion of the status bar.
- */
- gboolean GtkStatsMonitor::
- status_bar_button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) {
- GtkStatsMonitor *monitor = (GtkStatsMonitor *)data;
- GtkFlowBoxChild *child = gtk_flow_box_get_child_at_pos(
- GTK_FLOW_BOX(monitor->_status_bar), event->x, event->y);
- if (child == nullptr) {
- return FALSE;
- }
- // Which child is this?
- GList *children = gtk_container_get_children(GTK_CONTAINER(monitor->_status_bar));
- int index = g_list_index(children, child);
- g_list_free(children);
- if (index < 0 || (size_t)index >= monitor->_status_bar_labels.size()) {
- return FALSE;
- }
- const PStatClientData *client_data = monitor->get_client_data();
- if (client_data == nullptr) {
- return FALSE;
- }
- int collector = monitor->_status_bar_collectors[index];
- if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
- monitor->open_strip_chart(0, collector, collector != 0);
- // Also open a strip chart for other threads with data for this
- // collector.
- if (collector != 0) {
- for (int thread_index = 1; thread_index < client_data->get_num_threads(); ++thread_index) {
- PStatView &view = monitor->get_level_view(collector, thread_index);
- if (view.get_net_value() > 0.0) {
- monitor->open_strip_chart(thread_index, collector, true);
- }
- }
- }
- return TRUE;
- }
- else if (event->type == GDK_BUTTON_PRESS && event->button == 3 && index > 0) {
- PStatView &level_view = monitor->get_level_view(collector, 0);
- const PStatViewLevel *view_level = level_view.get_top_level();
- int num_children = view_level->get_num_children();
- if (num_children == 0) {
- return FALSE;
- }
- GtkWidget *menu = gtk_menu_new();
- // Reverse the order since the menus are listed from the top down; we want
- // to be visually consistent with the graphs, which list these labels from
- // the bottom up.
- for (int c = num_children - 1; c >= 0; c--) {
- const PStatViewLevel *child_level = view_level->get_child(c);
- int child_collector = child_level->get_collector();
- const MenuDef *menu_def = monitor->add_menu({0, child_collector, CT_strip_chart, true});
- double value = child_level->get_net_value();
- const PStatCollectorDef &def = client_data->get_collector_def(child_collector);
- std::string text = def._name;
- text += ": " + PStatGraph::format_number(value, PStatGraph::GBU_named | PStatGraph::GBU_show_units, def._level_units);
- GtkWidget *menu_item = gtk_menu_item_new_with_label(text.c_str());
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
- g_signal_connect(G_OBJECT(menu_item), "activate",
- G_CALLBACK(menu_activate),
- (void *)menu_def);
- }
- gtk_widget_show_all(menu);
- GtkWidget *label = monitor->_status_bar_labels[index];
- gtk_menu_popup_at_widget(GTK_MENU(menu), label,
- GDK_GRAVITY_NORTH_WEST,
- GDK_GRAVITY_SOUTH_WEST, nullptr);
- return TRUE;
- }
- return FALSE;
- }
- /**
- * Callback when a menu item is selected.
- */
- void GtkStatsMonitor::
- menu_activate(GtkWidget *widget, gpointer data) {
- const MenuDef &menu_def = *(const MenuDef *)data;
- GtkStatsMonitor *monitor = menu_def._monitor;
- if (monitor == nullptr) {
- return;
- }
- switch (menu_def._chart_type) {
- case CT_timeline:
- monitor->open_timeline();
- break;
- case CT_strip_chart:
- monitor->open_strip_chart(menu_def._thread_index,
- menu_def._collector_index,
- menu_def._show_level);
- break;
- case CT_flame_graph:
- monitor->open_flame_graph(menu_def._thread_index,
- menu_def._collector_index);
- break;
- case CT_piano_roll:
- monitor->open_piano_roll(menu_def._thread_index);
- break;
- case CT_choose_color:
- monitor->choose_collector_color(menu_def._collector_index);
- break;
- case CT_reset_color:
- monitor->reset_collector_color(menu_def._collector_index);
- break;
- }
- }
- /**
- * Called when a status bar item is double-clicked.
- */
- void GtkStatsMonitor::
- handle_status_bar_click(int item) {
- if (item == 0) {
- open_strip_chart(0, 0, false);
- }
- else if (item >= 1 && (size_t)item < _status_bar_collectors.size()) {
- int collector = _status_bar_collectors[item];
- open_strip_chart(0, collector, true);
- // Also open a strip chart for other threads with data for this
- // collector.
- const PStatClientData *client_data = get_client_data();
- for (int thread_index = 1; thread_index < client_data->get_num_threads(); ++thread_index) {
- PStatView &view = get_level_view(collector, thread_index);
- if (view.get_net_value() > 0.0) {
- open_strip_chart(thread_index, collector, true);
- }
- }
- }
- }
- /**
- * Called when a status bar item is right-clicked.
- */
- void GtkStatsMonitor::
- handle_status_bar_popup(int item) {
- if (item >= 0 && (size_t)item < _status_bar_collectors.size()) {
- int collector = _status_bar_collectors[item];
- PStatView &level_view = get_level_view(collector, 0);
- const PStatViewLevel *view_level = level_view.get_top_level();
- int num_children = view_level->get_num_children();
- if (num_children == 0) {
- return;
- }
- GtkWidget *menu = gtk_menu_new();
- // Reverse the order since the menus are listed from the top down; we want
- // to be visually consistent with the graphs, which list these labels from
- // the bottom up.
- const PStatClientData *client_data = get_client_data();
- for (int c = num_children - 1; c >= 0; c--) {
- const PStatViewLevel *child_level = view_level->get_child(c);
- int child_collector = child_level->get_collector();
- const MenuDef *menu_def = add_menu({0, child_collector, CT_strip_chart, true});
- double value = child_level->get_net_value();
- const PStatCollectorDef &def = client_data->get_collector_def(child_collector);
- std::string text = def._name;
- text += ": " + PStatGraph::format_number(value, PStatGraph::GBU_named | PStatGraph::GBU_show_units, def._level_units);
- GtkWidget *menu_item = gtk_menu_item_new_with_label(text.c_str());
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
- g_signal_connect(G_OBJECT(menu_item), "activate",
- G_CALLBACK(menu_activate),
- (void *)menu_def);
- }
- gtk_widget_show_all(menu);
- GtkWidget *label = _status_bar_labels[item];
- gtk_menu_popup_at_widget(GTK_MENU(menu), label,
- GDK_GRAVITY_NORTH_WEST,
- GDK_GRAVITY_SOUTH_WEST, nullptr);
- }
- }
|