Fix some Gtk::Menu memory leaks
authorRobin Gareus <robin@gareus.org>
Thu, 7 Mar 2019 16:02:12 +0000 (17:02 +0100)
committerRobin Gareus <robin@gareus.org>
Thu, 7 Mar 2019 22:50:50 +0000 (23:50 +0100)
A Gtk::manage()d widget will be deleted when its parent container
is destroyed. Top-level context menus are not inside a container and
hence need to be manually deallocated.

The solution here is to use a shared Gtk::Menu pointer that is
centrally de/re-allocated.

This works because the GUI is single-threaded and at most one
context menu is visible at a time.

gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/automation_controller.cc
gtk2_ardour/editor_summary.cc
gtk2_ardour/meter_strip.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_ui.cc
gtk2_ardour/session_dialog.cc
gtk2_ardour/visibility_group.cc
gtk2_ardour/visibility_group.h

index 6e8ca92d6c868136b52264047fe310c98c7492ea..c9a5ac8e1a1a5cdbd7cd9769dcbd50315441eed2 100644 (file)
@@ -287,6 +287,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , _was_dirty (false)
        , _mixer_on_top (false)
        , _initial_verbose_plugin_scan (false)
+       , _shared_popup_menu (0)
        , secondary_clock_spacer (0)
        , auto_input_button (ArdourButton::led_default_elements)
        , time_info_box (0)
@@ -868,6 +869,7 @@ ARDOUR_UI::~ARDOUR_UI ()
                delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
                delete nsm; nsm = 0;
                delete gui_object_state; gui_object_state = 0;
+               delete _shared_popup_menu ; _shared_popup_menu = 0;
                delete main_window_visibility;
                FastMeter::flush_pattern_cache ();
                ArdourFader::flush_pattern_cache ();
@@ -5433,7 +5435,7 @@ ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
 {
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = shared_popup_menu ();
        MenuList& items = m->items ();
 
        RadioMenuItem::Group group;
@@ -6024,3 +6026,14 @@ ARDOUR_UI::monitor_mono ()
        Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
        _monitor->set_mono (tact->get_active());
 }
+
+Gtk::Menu*
+ARDOUR_UI::shared_popup_menu ()
+{
+       ENSURE_GUI_THREAD (*this, &ARDOUR_UI::shared_popup_menu, ignored);
+
+       assert (!_shared_popup_menu || !_shared_popup_menu->is_visible());
+       delete _shared_popup_menu;
+       _shared_popup_menu = new Gtk::Menu;
+       return _shared_popup_menu;
+}
index db6b30fd6052f7738deca733fe10c360fd41338c..8ff4c3685f44943eb38b98f18dfa9866e77cfe0b 100644 (file)
@@ -228,6 +228,8 @@ public:
        PublicEditor&     the_editor() { return *editor;}
        Mixer_UI* the_mixer() { return mixer; }
 
+       Gtk::Menu* shared_popup_menu ();
+
        void new_midi_tracer_window ();
        void toggle_editing_space();
        void toggle_mixer_space();
@@ -401,6 +403,8 @@ private:
        bool          _mixer_on_top;
        bool          _initial_verbose_plugin_scan;
 
+       Gtk::Menu*    _shared_popup_menu;
+
        void hide_tabbable (ArdourWidgets::Tabbable*);
        void detach_tabbable (ArdourWidgets::Tabbable*);
        void attach_tabbable (ArdourWidgets::Tabbable*);
@@ -555,8 +559,6 @@ private:
 
        void transport_rec_enable_blink (bool onoff);
 
-       Gtk::Menu*        session_popup_menu;
-
        /* menu bar and associated stuff */
 
        Gtk::MenuBar* menu_bar;
index c7860c53cb5f5e89179ea8cc96980cc4dbae5731..aa37feabb3281721e5988f0983f7de70986977fe 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "widgets/ardour_button.h"
 #include "widgets/ardour_knob.h"
+
+#include "ardour_ui.h"
 #include "automation_controller.h"
 #include "gui_thread.h"
 #include "note_select_dialog.h"
@@ -301,14 +303,14 @@ AutomationController::on_button_release(GdkEventButton* ev)
 
        const ARDOUR::ParameterDescriptor& desc = _controllable->desc();
        if (desc.unit == ARDOUR::ParameterDescriptor::MIDI_NOTE) {
-               Gtk::Menu* menu  = manage(new Menu());
+               Gtk::Menu* menu  = ARDOUR_UI::instance()->shared_popup_menu ();
                MenuList&  items = menu->items();
                items.push_back(MenuElem(_("Select Note..."),
                                         sigc::mem_fun(*this, &AutomationController::run_note_select_dialog)));
                menu->popup(1, ev->time);
                return true;
        } else if (desc.unit == ARDOUR::ParameterDescriptor::HZ) {
-               Gtk::Menu* menu  = manage(new Menu());
+               Gtk::Menu* menu  = ARDOUR_UI::instance()->shared_popup_menu ();
                MenuList&  items = menu->items();
                items.push_back(MenuElem(_("Halve"),
                                         sigc::bind(sigc::mem_fun(*this, &AutomationController::set_ratio),
index 4ca37d191d458ef55768db8f3788ad411a4f321b..ab80917229a31bf6125b4cc559285949b1ac0886 100644 (file)
@@ -24,6 +24,7 @@
 #include <gtkmm/menu.h>
 #include <gtkmm/menuitem.h>
 
+#include "ardour_ui.h"
 #include "time_axis_view.h"
 #include "streamview.h"
 #include "editor_summary.h"
@@ -461,7 +462,7 @@ EditorSummary::on_button_press_event (GdkEventButton* ev)
 
        if (ev->button == 3) { // right-click:  show the reset menu action
                using namespace Gtk::Menu_Helpers;
-               Gtk::Menu* m = manage (new Gtk::Menu);
+               Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
                MenuList& items = m->items ();
                items.push_back(MenuElem(_("Reset Summary to Extents"),
                        sigc::mem_fun(*this, &EditorSummary::reset_to_extents)));
index e219a70d1c2fecc5240724484cba78d35e188283..ea6ace2af1944b37b1109bd4c61ef18481ff17b3 100644 (file)
@@ -40,6 +40,7 @@
 #include "widgets/tooltips.h"
 
 #include "gui_thread.h"
+#include "ardour_ui.h"
 #include "ardour_window.h"
 #include "ui_config.h"
 #include "utils.h"
@@ -837,7 +838,7 @@ MeterStrip::popup_level_meter_menu (GdkEventButton* ev)
 {
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
        MenuList& items = m->items ();
 
        RadioMenuItem::Group group;
@@ -888,7 +889,7 @@ MeterStrip::popup_name_label_menu (GdkEventButton* ev)
 {
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
        MenuList& items = m->items ();
 
        RadioMenuItem::Group group;
index 736e757675a48ff590309aa52e6d57063fea6920..052f08204ee4e18c951e1922d7f59b55bf10c2e6 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "widgets/tooltips.h"
 
+#include "ardour_ui.h"
 #include "ardour_window.h"
 #include "enums_convert.h"
 #include "mixer_strip.h"
@@ -2520,7 +2521,7 @@ MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
 {
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
        MenuList& items = m->items ();
 
        RadioMenuItem::Group group;
index 2f5c1b160b2294d6127a26006755335357af809d..679b98e41bcdcbb38e51c706a631d6c208d586c4 100644 (file)
@@ -2874,7 +2874,7 @@ Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
 {
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
        MenuList& items = m->items ();
 
        if (_selection.axes.empty()) {
index 6959d23d66d4f110699a383971af3b6e073cc2d2..148c9ed65155f323d1b90890bc6e86d2c75f9449 100644 (file)
@@ -1062,7 +1062,7 @@ SessionDialog::recent_context_mennu (GdkEventButton *ev)
        Gtk::TreeModel::Path tpath = recent_session_model->get_path(iter);
        const bool is_child = tpath.up () && tpath.up ();
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
        MenuList& items = m->items ();
        items.push_back (MenuElem (s, sigc::bind (sigc::hide_return (sigc::ptr_fun (&PBD::open_folder)), s)));
        if (!is_child) {
index d0ef1dd63510a0c36b9253a4421ab724410b2d06..10d5f98b730c34cdb5527031c2b0fde2c4be2386 100644 (file)
@@ -69,6 +69,7 @@ VisibilityGroup::button_press_event (GdkEventButton* ev)
                return false;
        }
 
+       /* memory leak: Gtk::Menu* */
        menu()->popup (1, ev->time);
        return true;
 }
index ce1adecdd46d804b7b46613d14eb49e2167bcbc1..d95497d9edec65281bfbf6c927e30447ca94bb08 100644 (file)
@@ -45,7 +45,6 @@ public:
                boost::function<boost::optional<bool> ()> = 0
                );
 
-       Gtk::Menu* menu ();
        Gtk::Widget* list_view ();
        bool button_press_event (GdkEventButton *);
        void update ();
@@ -87,6 +86,8 @@ private:
        void update_list_view ();
        bool should_actually_be_visible (Member const &) const;
 
+       Gtk::Menu* menu ();
+
        std::vector<Member> _members;
        std::string _xml_property_name;
        ModelColumns _model_columns;