From 676a6df593532539b8c4c4b6eea564abeee182f9 Mon Sep 17 00:00:00 2001 From: LD Date: Wed, 31 Jan 2024 21:24:49 +0100 Subject: [PATCH] pstats: Workaround for Gtk bug that causes UI to crash when a session is closed As workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2029, we manually create a GtkFlowBoxChild instance and attach the label to it and increase its reference count so it it not prematurely destroyed when removed from the GtkFlowBox, causing the UI to segfault. --- pandatool/src/gtk-stats/gtkStatsMonitor.cxx | 37 +++++++++++++++------ pandatool/src/gtk-stats/gtkStatsServer.cxx | 11 +++++- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx index 0a085668ac..0410504457 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx @@ -60,8 +60,9 @@ close() { remove_all_graphs(); - for (GtkWidget *label : _status_bar_labels) { - gtk_container_remove(GTK_CONTAINER(_status_bar), label); + for (GtkWidget *flow_box_child : _status_bar_labels) { + gtk_container_remove(GTK_CONTAINER(_status_bar), flow_box_child); + g_object_unref(flow_box_child); } _status_bar_collectors.clear(); _status_bar_labels.clear(); @@ -252,7 +253,8 @@ idle() { 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); + GtkWidget *label = gtk_bin_get_child(GTK_BIN(_status_bar_labels[0])); + gtk_label_set_text(GTK_LABEL(label), buffer); } } } @@ -607,9 +609,16 @@ update_status_bar() { size_t li = 1; collectors.push_back(0); if (_status_bar_labels.empty()) { + // As workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2029 + // We manually create a GtkFlowBoxChild instance and attach the label to it + // and increase its reference count so it it not prematurely destroyed when + // removed from the GtkFlowBox, causing the app to segfault. GtkWidget *label = gtk_label_new(""); - gtk_container_add(GTK_CONTAINER(_status_bar), label); - _status_bar_labels.push_back(label); + GtkWidget *flow_box_child = gtk_flow_box_child_new(); + gtk_container_add(GTK_CONTAINER(flow_box_child), label); + gtk_container_add(GTK_CONTAINER(_status_bar), flow_box_child); + _status_bar_labels.push_back(flow_box_child); + g_object_ref(flow_box_child); } // Gather the top-level collector list. @@ -639,15 +648,21 @@ update_status_bar() { std::string text = def._name; text += ": " + PStatGraph::format_number(value, PStatGraph::GBU_named | PStatGraph::GBU_show_units, def._level_units); + GtkWidget *flow_box_child; GtkWidget *label; if (li < _status_bar_labels.size()) { - label = _status_bar_labels[li++]; + flow_box_child = _status_bar_labels[li++]; + label = gtk_bin_get_child(GTK_BIN(flow_box_child)); 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); + // See comment above + flow_box_child = gtk_flow_box_child_new(); + gtk_container_add(GTK_CONTAINER(flow_box_child), label); + gtk_container_add(GTK_CONTAINER(_status_bar), flow_box_child); + _status_bar_labels.push_back(flow_box_child); + g_object_ref(flow_box_child); } collectors.push_back(collector); @@ -737,7 +752,8 @@ status_bar_button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) gtk_widget_show_all(menu); - GtkWidget *label = monitor->_status_bar_labels[index]; + GtkWidget *flow_box_child = monitor->_status_bar_labels[index]; + GtkWidget *label = gtk_bin_get_child(GTK_BIN(flow_box_child)); gtk_menu_popup_at_widget(GTK_MENU(menu), label, GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_SOUTH_WEST, nullptr); @@ -855,7 +871,8 @@ handle_status_bar_popup(int item) { gtk_widget_show_all(menu); - GtkWidget *label = _status_bar_labels[item]; + GtkWidget *flow_box_child = _status_bar_labels[item]; + GtkWidget *label = gtk_bin_get_child(GTK_BIN(flow_box_child)); gtk_menu_popup_at_widget(GTK_MENU(menu), label, GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_SOUTH_WEST, nullptr); diff --git a/pandatool/src/gtk-stats/gtkStatsServer.cxx b/pandatool/src/gtk-stats/gtkStatsServer.cxx index ce7f99e1e9..25fdba2ee9 100644 --- a/pandatool/src/gtk-stats/gtkStatsServer.cxx +++ b/pandatool/src/gtk-stats/gtkStatsServer.cxx @@ -123,6 +123,7 @@ make_monitor(const NetAddress &address) { if (_status_bar_label != nullptr) { gtk_container_remove(GTK_CONTAINER(_status_bar), _status_bar_label); + g_object_unref(_status_bar_label); _status_bar_label = nullptr; } @@ -177,9 +178,16 @@ new_session() { std::ostringstream strm; strm << "Waiting for client to connect on port " << _port << "..."; std::string title = strm.str(); - _status_bar_label = gtk_label_new(title.c_str()); + // As workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2029 + // We manually create a GtkFlowBoxChild instance and attach the label to it + // and increase its reference count so it it not prematurely destroyed when + // removed from the GtkFlowBox, causing the app to segfault. + GtkWidget * label = gtk_label_new(title.c_str()); + _status_bar_label = gtk_flow_box_child_new(); + gtk_container_add(GTK_CONTAINER(_status_bar_label), label); gtk_container_add(GTK_CONTAINER(_status_bar), _status_bar_label); gtk_widget_show(_status_bar_label); + g_object_ref(_status_bar_label); } gtk_widget_set_sensitive(_new_session_menu_item, FALSE); @@ -462,6 +470,7 @@ close_session() { if (_status_bar_label != nullptr) { gtk_container_remove(GTK_CONTAINER(_status_bar), _status_bar_label); + g_object_unref(_status_bar_label); _status_bar_label = nullptr; }