First go at saving window visibility and position state across saves.
authorCarl Hetherington <carl@carlh.net>
Wed, 18 Aug 2010 02:20:15 +0000 (02:20 +0000)
committerCarl Hetherington <carl@carlh.net>
Wed, 18 Aug 2010 02:20:15 +0000 (02:20 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@7644 d708f5d6-7413-0410-9779-e7cbd77b26cf

22 files changed:
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/ardour_ui2.cc
gtk2_ardour/ardour_ui_dialogs.cc
gtk2_ardour/ardour_ui_ed.cc
gtk2_ardour/automation_time_axis.h
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_strip.h
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/public_editor.h
gtk2_ardour/route_time_axis.cc
gtk2_ardour/selection.cc
gtk2_ardour/selection.h
gtk2_ardour/window_proxy.cc [new file with mode: 0755]
gtk2_ardour/window_proxy.h [new file with mode: 0755]
gtk2_ardour/wscript
libs/ardour/ardour/processor.h
libs/ardour/processor.cc

index f1120ccfca56e817554fc81bdd97a5aa7f836f85..837dfd9ba2b0c4301c68146db1b0490d8cd98632 100644 (file)
@@ -98,6 +98,9 @@ typedef uint64_t microseconds_t;
 #include "engine_dialog.h"
 #include "processor_box.h"
 #include "time_axis_view_item.h"
+#include "window_proxy.h"
+#include "global_port_matrix.h"
+#include "location_ui.h"
 
 #include "i18n.h"
 
@@ -164,7 +167,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
 
          auditioning_alert_button (_("AUDITION")),
          solo_alert_button (_("SOLO")),
-         shown_flag (false),
          error_log_button (_("Errors"))
 
 {
@@ -290,6 +292,21 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
 
         TimeAxisViewItem::set_constant_heights ();
 
+       /* The following must happen after ARDOUR::init() so that Config is set up */
+       
+       location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
+       big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
+       
+       for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
+               _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
+                       string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
+                       Config->extra_xml (X_("UI")),
+                       string_compose ("toggle-%1-connection-manager", (*i).to_string())
+                       );
+       }
+
+       setup_clock ();
+
        starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
        stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
 
@@ -660,8 +677,16 @@ ARDOUR_UI::startup ()
 
        goto_editor_window ();
 
+       /* Add the window proxies here; their addition may cause windows to be opened, and we want them
+          to be opened on top of the editor window that goto_editor_window() just opened.
+       */
+       add_window_proxy (location_ui);
+       add_window_proxy (big_clock_window);
+       for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
+               add_window_proxy (_global_port_matrix[*i]);
+       }
+       
        BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
-       show ();
 }
 
 void
@@ -784,17 +809,22 @@ If you still wish to quit, please use the\n\n\
                point_one_second_connection.disconnect ();
                point_oh_five_second_connection.disconnect ();
                point_zero_one_second_connection.disconnect();
-               
-                _session->set_clean ();
+       }
+
+       /* Save state before deleting the session, as that causes some
+          windows to be destroyed before their visible state can be
+          saved.
+       */
+       save_ardour_state ();
+
+       if (_session) {
                // _session->set_deletion_in_progress ();
+                _session->set_clean ();
                _session->remove_pending_capture_state ();
                delete _session;
                _session = 0;
        }
 
-        cerr << "Save before quit\n";
-       save_ardour_state ();
-
        ArdourDialog::close_all_dialogs ();
        engine->stop (true);
        quit ();
@@ -2571,7 +2601,6 @@ ARDOUR_UI::close_session()
        }
 
        goto_editor_window ();
-       show ();
 }
 
 int
@@ -2725,20 +2754,6 @@ ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_n
        return 0;
 }
 
-void
-ARDOUR_UI::show ()
-{
-       if (editor) {
-               editor->show_window ();
-
-               if (!shown_flag) {
-                       editor->present ();
-               }
-
-               shown_flag = true;
-       }
-}
-
 void
 ARDOUR_UI::launch_chat ()
 {
@@ -3355,22 +3370,10 @@ ARDOUR_UI::reconnect_to_jack ()
 void
 ARDOUR_UI::use_config ()
 {
-
        XMLNode* node = Config->extra_xml (X_("TransportControllables"));
        if (node) {
                set_transport_controllable_state (*node);
        }
-
-       node = Config->extra_xml (X_("UI"));
-
-        if (node) {
-                const XMLProperty* prop = node->property (X_("show-big-clock"));
-                Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
-                if (act) {
-                        Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-                        tact->set_active (string_is_affirmative (prop->value()));
-                }
-        }
 }
 
 void
@@ -3388,7 +3391,7 @@ ARDOUR_UI::update_transport_clocks (nframes_t pos)
                secondary_clock.set (pos);
        }
 
-       if (big_clock_window) {
+       if (big_clock_window->get()) {
                big_clock.set (pos);
        }
 }
@@ -3414,7 +3417,7 @@ ARDOUR_UI::record_state_changed ()
 {
        ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
 
-       if (!_session || !big_clock_window) {
+       if (!_session || !big_clock_window->get()) {
                /* why bother - the clock isn't visible */
                return;
        }
@@ -3614,3 +3617,23 @@ ARDOUR_UI::toggle_translations ()
                 }
         }
 }        
+
+/** Add a window proxy to our list, so that its state will be saved.
+ *  This call also causes the window to be created and opened if its
+ *  state was saved as `visible'.
+ */
+void
+ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
+{
+       _window_proxies.push_back (p);
+       p->maybe_show ();
+}
+
+/** Remove a window proxy from our list.  Must be called if a WindowProxy
+ *  is deleted, to prevent hanging pointers.
+ */
+void
+ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
+{
+       _window_proxies.remove (p);
+}
index cccc4ab5b015fe7be59972b87ce7650c9ec9d911..bf9a88d29e8ff433d05475ca3349797a4259bc1a 100644 (file)
@@ -67,6 +67,7 @@
 #include "ardour_dialog.h"
 #include "editing.h"
 #include "ui_config.h"
+#include "window_proxy.h"
 
 class About;
 class AddRouteDialog;
@@ -85,6 +86,8 @@ class SessionOptionEditor;
 class Splash;
 class ThemeManager;
 class MidiTracer;
+class WindowProxyBase;
+class GlobalPortMatrixWindow;
 
 namespace Gtkmm2ext {
        class TearOff;
@@ -110,9 +113,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
 
        bool run_startup (bool should_be_new, std::string load_template);
 
-       void show ();
-       bool shown() { return shown_flag; }
-
        void show_splash ();
        void hide_splash ();
 
@@ -233,6 +233,9 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
 
        void set_shuttle_fract (double);
 
+       void add_window_proxy (WindowProxyBase *);
+       void remove_window_proxy (WindowProxyBase *);
+       
   protected:
        friend class PublicEditor;
 
@@ -313,7 +316,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
        void manage_window (Gtk::Window&);
 
        AudioClock   big_clock;
-       Gtk::Window* big_clock_window;
+       ActionWindowProxy<Gtk::Window>* big_clock_window;
         int original_big_clock_width;
         int original_big_clock_height;
         double original_big_clock_font_size;
@@ -588,10 +591,13 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
        BundleManager *bundle_manager;
        void create_bundle_manager ();
 
-       LocationUIWindow *location_ui;
+       ActionWindowProxy<LocationUIWindow>* location_ui;
        int               create_location_ui ();
        void              handle_locations_change (ARDOUR::Location*);
 
+       ActionWindowProxy<GlobalPortMatrixWindow>* _global_port_matrix[ARDOUR::DataType::num_types];
+       void toggle_global_port_matrix (ARDOUR::DataType);
+
        static UIConfiguration *ui_config;
        ThemeManager *theme_manager;
 
@@ -625,7 +631,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
        About* about;
        Splash* splash;
        void pop_back_splash ();
-       bool shown_flag;
 
        /* cleanup */
 
@@ -707,6 +712,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
         */
        bool idle_finish ();
        void queue_finish ();
+
+       std::list<WindowProxyBase*> _window_proxies;
 };
 
 #endif /* __ardour_gui_h__ */
index 62b827d61a3c0dd426152f4e04a865055ee1b8a8..65f165aa6e1642d4c8a9b79f52a83c9f9818da8a 100644 (file)
@@ -46,6 +46,8 @@
 #include "utils.h"
 #include "theme_manager.h"
 #include "midi_tracer.h"
+#include "global_port_matrix.h"
+#include "location_ui.h"
 
 #include "i18n.h"
 
@@ -103,7 +105,6 @@ ARDOUR_UI::setup_windows ()
 
        editor->add_toplevel_controls (top_packer);
 
-       setup_clock ();
        setup_transport();
        build_menu_bar ();
 
index 747354ca4e8a02c09c978be0e2f6dd9249ba7845..6a0bbb0a7e6b042fcc5f7a311ea03f7ffe25c23a 100644 (file)
@@ -41,6 +41,7 @@
 #include "gui_thread.h"
 #include "midi_tracer.h"
 #include "add_route_dialog.h"
+#include "global_port_matrix.h"
 
 #include "i18n.h"
 
@@ -59,8 +60,8 @@ ARDOUR_UI::set_session (Session *s)
                return;
        }
 
-       if (location_ui) {
-               location_ui->set_session(s);
+       if (location_ui->get()) {
+               location_ui->get()->set_session(s);
        }
 
        if (route_params) {
@@ -75,6 +76,12 @@ ARDOUR_UI::set_session (Session *s)
                session_option_editor->set_session (s);
        }
 
+       for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
+               if (_global_port_matrix[*i]->get()) {
+                       _global_port_matrix[*i]->get()->set_session (_session);
+               }
+       }
+
        primary_clock.set_session (s);
        secondary_clock.set_session (s);
        big_clock.set_session (s);
@@ -217,10 +224,10 @@ ARDOUR_UI::toggle_big_clock_window ()
                RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
                if (tact->get_active()) {
-                       big_clock_window->show_all ();
-                       big_clock_window->present ();
+                       big_clock_window->get()->show_all ();
+                       big_clock_window->get()->present ();
                } else {
-                       big_clock_window->hide ();
+                       big_clock_window->get()->hide ();
                }
        }
 }
@@ -297,9 +304,9 @@ int
 ARDOUR_UI::create_location_ui ()
 {
        if (location_ui == 0) {
-               location_ui = new LocationUIWindow ();
-               location_ui->set_session (_session);
-               location_ui->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleLocations")));
+               location_ui->set (new LocationUIWindow ());
+               location_ui->get()->set_session (_session);
+               location_ui->get()->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleLocations")));
        }
        return 0;
 }
@@ -316,10 +323,10 @@ ARDOUR_UI::toggle_location_window ()
                RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
                if (tact->get_active()) {
-                       location_ui->show_all ();
-                       location_ui->present ();
+                       location_ui->get()->show_all ();
+                       location_ui->get()->present ();
                } else {
-                       location_ui->hide ();
+                       location_ui->get()->hide ();
                }
        }
 }
index efdbd13add09738f4f2e0f1821860cbc23bf95fa..091d846c1bec8514297f5bfd9fc815ef447e8c83 100644 (file)
@@ -47,6 +47,8 @@
 #include "mixer_ui.h"
 #include "startup.h"
 #include "utils.h"
+#include "window_proxy.h"
+#include "global_port_matrix.h"
 
 #include <gtkmm2ext/application.h>
 
@@ -68,7 +70,6 @@ using namespace Glib;
 
 int
 ARDOUR_UI::create_editor ()
-
 {
        try {
                editor = new Editor ();
@@ -225,6 +226,10 @@ ARDOUR_UI::install_actions ()
        ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_toggle_action (common_actions, X_("ToggleBigClock"), _("Big Clock"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_big_clock_window));
        ActionManager::session_sensitive_actions.push_back (act);
+       act = ActionManager::register_toggle_action (common_actions, X_("toggle-audio-connection-manager"), _("Audio Connection Manager"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::toggle_global_port_matrix), ARDOUR::DataType::AUDIO));
+       ActionManager::session_sensitive_actions.push_back (act);
+       act = ActionManager::register_toggle_action (common_actions, X_("toggle-midi-connection-manager"), _("MIDI Connection Manager"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::toggle_global_port_matrix), ARDOUR::DataType::MIDI));
+       ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_action (common_actions, X_("NewMIDITracer"), _("MIDI Tracer"), sigc::mem_fun(*this, &ARDOUR_UI::new_midi_tracer_window));
        ActionManager::session_sensitive_actions.push_back (act);
        ActionManager::register_action (common_actions, X_("About"), _("About"),  sigc::mem_fun(*this, &ARDOUR_UI::show_about));
@@ -555,20 +560,20 @@ ARDOUR_UI::setup_clock ()
 {
        ARDOUR_UI::Clock.connect (sigc::bind (sigc::mem_fun (big_clock, &AudioClock::set), false));
 
-       big_clock_window = new Window (WINDOW_TOPLEVEL);
+       big_clock_window->set (new Window (WINDOW_TOPLEVEL));
 
-       big_clock_window->set_keep_above (true);
-       big_clock_window->set_border_width (0);
-       big_clock_window->add  (big_clock);
+       big_clock_window->get()->set_keep_above (true);
+       big_clock_window->get()->set_border_width (0);
+       big_clock_window->get()->add (big_clock);
 
-       big_clock_window->set_title (_("Big Clock"));
-       big_clock_window->set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
-       big_clock_window->signal_realize().connect (sigc::mem_fun (*this, &ARDOUR_UI::big_clock_realized));
-       big_clock_window->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBigClock")));
-       big_clock_window->signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), big_clock_window), false);
-       big_clock_window->signal_size_allocate().connect (sigc::mem_fun (*this, &ARDOUR_UI::big_clock_size_allocate));
+       big_clock_window->get()->set_title (_("Big Clock"));
+       big_clock_window->get()->set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
+       big_clock_window->get()->signal_realize().connect (sigc::mem_fun (*this, &ARDOUR_UI::big_clock_realized));
+       big_clock_window->get()->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBigClock")));
+       big_clock_window->get()->signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), big_clock_window->get()), false);
+       big_clock_window->get()->signal_size_allocate().connect (sigc::mem_fun (*this, &ARDOUR_UI::big_clock_size_allocate));
 
-       manage_window (*big_clock_window);
+       manage_window (*big_clock_window->get());
 }
 
 void
@@ -576,8 +581,8 @@ ARDOUR_UI::big_clock_realized ()
 {
        int x, y, w, d;
 
-       set_decoration (big_clock_window, (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
-       big_clock_window->get_window()->get_geometry (x, y, w, big_clock_height, d);
+       set_decoration (big_clock_window->get(), (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
+       big_clock_window->get()->get_window()->get_geometry (x, y, w, big_clock_height, d);
 
         original_big_clock_height = big_clock_height;
         original_big_clock_width = w;
@@ -588,45 +593,6 @@ ARDOUR_UI::big_clock_realized ()
         if (!fd.get_size_is_absolute ()) {
                 original_big_clock_font_size /= PANGO_SCALE;
         }
-
-        /* we can't set the real size until we know the original one, with the UI rc-file-set font 
-           size, so do this here.
-        */
-
-       XMLNode* node = Config->extra_xml (X_("UI"));
-
-       if (node) {
-
-               const XMLProperty* prop;
-                int w, h, x, y;
-                int have_pos = 0;
-
-                w = h = x = y = 0;
-
-                if ((prop = node->property ("big-clock-x-size")) != 0) {
-                        w = atoi (prop->value());
-                }
-                if ((prop = node->property ("big-clock-y-size")) != 0) {
-                        h = atoi (prop->value());
-                }
-
-                if (w && h) {
-                        big_clock_window->set_default_size (w, h);
-                }
-
-                if ((prop = node->property ("big-clock-x-off")) != 0) {
-                        x = atoi (prop->value());
-                        have_pos++;
-                }
-                if ((prop = node->property ("big-clock-y-off")) != 0) {
-                        y = atoi (prop->value());
-                        have_pos++;
-                }
-
-                if (have_pos == 2) {
-                        big_clock_window->move (x, y);
-                }
-        }
 }
 
 void
@@ -634,9 +600,9 @@ ARDOUR_UI::float_big_clock (Gtk::Window* parent)
 {
        if (big_clock_window) {
                if (parent) {
-                       big_clock_window->set_transient_for (*parent);
+                       big_clock_window->get()->set_transient_for (*parent);
                } else {
-                       gtk_window_set_transient_for (big_clock_window->gobj(), (GtkWindow*) 0);
+                       gtk_window_set_transient_for (big_clock_window->get()->gobj(), (GtkWindow*) 0);
                }
        }
 }
@@ -655,7 +621,7 @@ ARDOUR_UI::idle_big_clock_text_resizer (int win_w, int win_h)
 {
        big_clock_resize_in_progress = false;
 
-       Glib::RefPtr<Gdk::Window> win = big_clock_window->get_window();
+       Glib::RefPtr<Gdk::Window> win = big_clock_window->get()->get_window();
        Pango::FontDescription fd (big_clock.get_style()->get_font());
        int current_size = fd.get_size ();
         int x, y, w, h, d;
@@ -708,30 +674,11 @@ ARDOUR_UI::save_ardour_state ()
        Config->add_extra_xml (get_transport_controllable_state());
 
         XMLNode* window_node = new XMLNode (X_("UI"));
-        
-        window_node->add_property ("show-big-clock", (big_clock_window && big_clock_window->is_visible() ? "yes" : "no"));
-
-        Glib::RefPtr<Gdk::Window> win;
-
-        if (big_clock_window && (win = big_clock_window->get_window())) {
-
-                int w, h;
-                int xoff, yoff;
-                char buf[32];
-
-                win->get_size (w, h);
-                win->get_position (xoff, yoff);
-
-                snprintf (buf, sizeof (buf), "%d", w);
-                window_node->add_property ("big-clock-x-size", buf);
-                snprintf (buf, sizeof (buf), "%d", h);
-                window_node->add_property ("big-clock-y-size", buf);
-                snprintf (buf, sizeof (buf), "%d", xoff);
-                window_node->add_property ("big-clock-x-off", buf);
-                snprintf (buf, sizeof (buf), "%d", yoff);
-                window_node->add_property ("big-clock-y-off", buf);
-        }
 
+       for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
+               window_node->add_child_nocopy (*((*i)->get_state ()));
+       }
+        
         /* tearoffs */
 
         XMLNode* tearoff_node = new XMLNode (X_("Tearoffs"));
@@ -778,3 +725,17 @@ ARDOUR_UI::save_ardour_state ()
        Keyboard::save_keybindings ();
 }
 
+void
+ARDOUR_UI::toggle_global_port_matrix (ARDOUR::DataType t)
+{
+       if (_global_port_matrix[t]->get() == 0) {
+               _global_port_matrix[t]->set (new GlobalPortMatrixWindow (_session, t));
+       }
+
+       if (_global_port_matrix[t]->get()->is_visible ()) {
+               _global_port_matrix[t]->get()->hide ();
+       } else {
+               _global_port_matrix[t]->get()->present ();
+       }
+}
+
index 8daccf97eb25262583c033a9c7e0c536b2de4979..c4132269f16f4126330c3e800f2194ebcd470877 100644 (file)
@@ -107,6 +107,10 @@ class AutomationTimeAxisView : public TimeAxisView {
 
        bool has_automation () const;
 
+       boost::shared_ptr<ARDOUR::Route> parent_route () {
+               return _route;
+       }
+
   protected:
        boost::shared_ptr<ARDOUR::Route> _route; ///< Parent route
        boost::shared_ptr<ARDOUR::AutomationControl> _control; ///< Control
index 097a7cf41859a6f6edf7ffa7b6526468f3c40dba..adfbf5293a936c739fa99a5fcfc703213aca1caa 100644 (file)
@@ -385,9 +385,6 @@ Editor::Editor ()
        select_new_marker = false;
        rhythm_ferret = 0;
        _bundle_manager = 0;
-       for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
-               _global_port_matrix[*i] = 0;
-       }
        no_save_visual = false;
        resize_idle_id = -1;
 
@@ -668,9 +665,6 @@ Editor::Editor ()
        set_mouse_mode (MouseObject, true);
        set_edit_point_preference (EditAtMouse, true);
 
-       XMLNode* node = ARDOUR_UI::instance()->editor_settings();
-       set_state (*node, Stateful::loading_state_version);
-
        _playlist_selector = new PlaylistSelector();
        _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
 
@@ -1079,12 +1073,6 @@ Editor::set_session (Session *t)
                sfbrowser->set_session (_session);
        }
 
-       for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
-               if (_global_port_matrix[*i]) {
-                       _global_port_matrix[*i]->set_session (_session);
-               }
-       }
-
        compute_fixed_ruler_scale ();
 
        /* there are never any selected regions at startup */
@@ -2555,6 +2543,11 @@ Editor::set_state (const XMLNode& node, int /*version*/)
                the_notebook.set_current_page (atoi (prop->value ()));
        }
 
+       XMLNodeList children = node.children ();
+       for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+               selection->set_state (**i, Stateful::current_state_version);
+       }
+
        return 0;
 }
 
@@ -2641,6 +2634,8 @@ Editor::get_state ()
        snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
        node->add_property (X_("editor-list-page"), buf);
 
+       node->add_child_nocopy (selection->get_state ());
+       
        return *node;
 }
 
@@ -4905,16 +4900,6 @@ Editor::show_rhythm_ferret ()
        rhythm_ferret->present ();
 }
 
-void
-Editor::show_global_port_matrix (ARDOUR::DataType t)
-{
-       if (_global_port_matrix[t] == 0) {
-               _global_port_matrix[t] = new GlobalPortMatrixWindow (_session, t);
-       }
-
-       _global_port_matrix[t]->show ();
-}
-
 void
 Editor::first_idle ()
 {
@@ -5200,12 +5185,13 @@ Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
        }
 }
 
+/** Find a RouteTimeAxisView by the ID of its route */
 RouteTimeAxisView*
-Editor::get_route_view_by_id (PBD::ID& id)
+Editor::get_route_view_by_route_id (PBD::ID& id) const
 {
        RouteTimeAxisView* v;
 
-       for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+       for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
                if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
                        if(v->route()->id() == id) {
                                return v;
index 45ef788d40d63ee548291cfb77bdb961d6bd3c7c..22f68c23ce165f6b92be631c70143dd7e369d430 100644 (file)
@@ -65,6 +65,7 @@
 #include "editor_items.h"
 #include "region_selection.h"
 #include "canvas.h"
+#include "window_proxy.h"
 
 namespace Gnome { namespace Canvas {
        class NoEventText;
@@ -106,7 +107,6 @@ class BundleManager;
 class ControlPoint;
 class CrossfadeView;
 class DragManager;
-class GlobalPortMatrixWindow;
 class GroupedButtons;
 class Marker;
 class MidiRegionView;
@@ -213,7 +213,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void foreach_time_axis_view (sigc::slot<void,TimeAxisView&>);
        void add_to_idle_resize (TimeAxisView*, int32_t);
 
-       RouteTimeAxisView* get_route_view_by_id (PBD::ID& id);
+       RouteTimeAxisView* get_route_view_by_route_id (PBD::ID& id) const;
 
        void consider_auditioning (boost::shared_ptr<ARDOUR::Region>);
        void hide_a_region (boost::shared_ptr<ARDOUR::Region>);
@@ -413,7 +413,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void toggle_meter_updating();
 
        void show_rhythm_ferret();
-       void show_global_port_matrix (ARDOUR::DataType);
 
        void goto_visual_state (uint32_t);
        void save_visual_state (uint32_t);
@@ -2003,7 +2002,6 @@ public:
 
        RhythmFerret* rhythm_ferret;
        BundleManager* _bundle_manager;
-       GlobalPortMatrixWindow* _global_port_matrix[ARDOUR::DataType::num_types];
 
        void fit_tracks (TrackViewList &);
        void fit_selected_tracks ();
index 8c70c4d14869664d5ab21ad70b3434b5a3bea968..e8eeb4d5727f03ebdaa8f5f7e0fdea037e1b55c2 100644 (file)
@@ -542,10 +542,6 @@ Editor::register_actions ()
        act = ActionManager::register_action (editor_actions, "toggle-rhythm-ferret", _("Rhythm Ferret..."), sigc::mem_fun(*this, &Editor::show_rhythm_ferret));
        ActionManager::session_sensitive_actions.push_back (act);
        ActionManager::region_selection_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "toggle-audio-connection-manager", _("Audio Connection Manager"), sigc::bind (sigc::mem_fun (*this, &Editor::show_global_port_matrix), ARDOUR::DataType::AUDIO));
-       ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "toggle-midi-connection-manager", _("MIDI Connection Manager"), sigc::bind (sigc::mem_fun (*this, &Editor::show_global_port_matrix), ARDOUR::DataType::MIDI));
-       ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_action (editor_actions, "toggle-log-window", _("Log"),
                        sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::toggle_errors));
        ActionManager::session_sensitive_actions.push_back (act);
index ecd1b733beaed0640a8b9bfff3bdcfb9721281d5..4523ca524a6210cee58c88b1ac7fa7b9246f8e2d 100644 (file)
@@ -362,6 +362,8 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
                button_table.remove (*show_sends_button);
        }
 
+       processor_box.set_route (rt);
+
        RouteUI::set_route (rt);
 
        /* map the current state */
@@ -377,8 +379,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
 
        revert_to_default_display ();
 
-       processor_box.set_route (rt);
-
        if (set_color_from_route()) {
                set_color (unique_random_color());
        }
@@ -1540,6 +1540,7 @@ MixerStrip::map_frozen ()
                switch (at->freeze_state()) {
                case AudioTrack::Frozen:
                        processor_box.set_sensitive (false);
+                       hide_redirect_editors ();
                        break;
                default:
                        processor_box.set_sensitive (true);
@@ -1547,8 +1548,6 @@ MixerStrip::map_frozen ()
                        break;
                }
        }
-
-       hide_redirect_editors ();
 }
 
 void
@@ -1565,10 +1564,10 @@ MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
                return;
        }
 
-       void* gui = processor->get_gui ();
+       Gtk::Window* w = processor_box.get_processor_ui (processor);
 
-       if (gui) {
-               static_cast<Gtk::Widget*>(gui)->hide ();
+       if (w) {
+               w->hide ();
        }
 }
 
index 0d3878fc2016d20da726fa3d1fcbb7cb12b51534..bbebbcaf15e0791a6b77604dde42cb64bc64f97b 100644 (file)
@@ -99,6 +99,10 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
        void set_button_names ();
        void show_send (boost::shared_ptr<ARDOUR::Send>);
 
+       bool mixer_owned () const {
+               return _mixer_owned;
+       }
+
        sigc::signal<void>      WidthChanged;
 
        static sigc::signal<void,boost::shared_ptr<ARDOUR::Route> > SwitchIO;
index cc322df13d060a00583ed68ee4f7c0df7cf1f13f..8840c773f98c3c9dacefbfcefe6e527c0e06b14c 100644 (file)
@@ -392,28 +392,6 @@ ProcessorBox::set_width (Width w)
        redisplay_processors ();
 }
 
-void
-ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
-{
-       boost::shared_ptr<Send> send;
-       boost::shared_ptr<Return> retrn;
-       boost::shared_ptr<PortInsert> port_insert;
-
-       if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
-               PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui());
-               port_insert->set_gui (0);
-               delete io_selector;
-       } else if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
-               SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
-               send->set_gui (0);
-               delete sui;
-       } else if ((retrn = boost::dynamic_pointer_cast<Return> (processor)) != 0) {
-               ReturnUIWindow *rui = reinterpret_cast<ReturnUIWindow*> (retrn->get_gui());
-               retrn->set_gui (0);
-               delete rui;
-       }
-}
-
 void
 ProcessorBox::build_send_action_menu ()
 {
@@ -958,6 +936,73 @@ ProcessorBox::redisplay_processors ()
        _route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::add_processor_to_display));
 
        build_processor_tooltip (processor_eventbox, _("Inserts, sends & plugins:"));
+
+       _route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::maybe_add_processor_to_ui_list));
+
+       /* trim dead wood from the processor window proxy list */
+
+       list<ProcessorWindowProxy*>::iterator i = _processor_window_proxies.begin();
+       while (i != _processor_window_proxies.end()) {
+               list<ProcessorWindowProxy*>::iterator j = i;
+               ++j;
+
+               if (!(*i)->marked) {
+                       ARDOUR_UI::instance()->remove_window_proxy (*i);
+                       _processor_window_proxies.erase (i);
+                       delete *i;
+               }
+
+               i = j;
+       }
+}
+
+/** Add a ProcessorWindowProxy for a processor to our list, if that processor does
+ *  not already have one.
+ */
+void
+ProcessorBox::maybe_add_processor_to_ui_list (boost::weak_ptr<Processor> w)
+{
+       boost::shared_ptr<Processor> p = w.lock ();
+       if (!p) {
+               return;
+       }
+
+       list<ProcessorWindowProxy*>::iterator i = _processor_window_proxies.begin ();
+       while (i != _processor_window_proxies.end()) {
+
+               boost::shared_ptr<Processor> t = (*i)->processor().lock ();
+               
+               if (p == t) {
+                       /* this processor is already on the list; done */
+                       (*i)->marked = true;
+                       return;
+               }
+
+               ++i;
+       }
+
+       /* not on the list; add it */
+
+       string loc;
+       if (_parent_strip) {
+               if (_parent_strip->mixer_owned()) {
+                       loc = X_("M");
+               } else {
+                       loc = X_("R");
+               }
+       } else {
+               loc = X_("P");
+       }
+       
+       ProcessorWindowProxy* wp = new ProcessorWindowProxy (
+               string_compose ("%1-%2-%3", loc, _route->id(), p->id()),
+               Config->extra_xml (X_("UI")),
+               this,
+               w);
+       
+       wp->marked = true;
+       _processor_window_proxies.push_back (wp);
+       ARDOUR_UI::instance()->add_window_proxy (wp);
 }
 
 void
@@ -1102,10 +1147,10 @@ ProcessorBox::cut_processors (const ProcSelection& to_be_removed)
                    (boost::dynamic_pointer_cast<Send>((*i)) != 0) ||
                    (boost::dynamic_pointer_cast<Return>((*i)) != 0)) {
 
-                       void* gui = (*i)->get_gui ();
+                       Window* w = get_processor_ui (*i);
 
-                       if (gui) {
-                               static_cast<Gtk::Widget*>(gui)->hide ();
+                       if (w) {
+                               w->hide ();
                        }
 
                        XMLNode& child ((*i)->get_state());
@@ -1174,10 +1219,10 @@ ProcessorBox::delete_processors (const ProcSelection& targets)
 
        for (ProcSelection::const_iterator i = targets.begin(); i != targets.end(); ++i) {
 
-               void* gui = (*i)->get_gui ();
+               Window* w = get_processor_ui (*i);
 
-               if (gui) {
-                       static_cast<Gtk::Widget*>(gui)->hide ();
+               if (w) {
+                       w->hide ();
                }
 
                _route->remove_processor(*i);
@@ -1195,10 +1240,10 @@ ProcessorBox::delete_dragged_processors (const list<boost::shared_ptr<Processor>
        no_processor_redisplay = true;
        for (x = procs.begin(); x != procs.end(); ++x) {
 
-               void* gui = (*x)->get_gui ();
+               Window* w = get_processor_ui (*x);
 
-               if (gui) {
-                       static_cast<Gtk::Widget*>(gui)->hide ();
+               if (w) {
+                       w->hide ();
                }
 
                _route->remove_processor(*x);
@@ -1488,13 +1533,14 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
 #ifdef OLD_SEND_EDITING
                SendUIWindow *send_ui;
 
-               if (send->get_gui() == 0) {
+               Window* w = get_processor_ui (send);
+               if (w == 0) {
                        send_ui = new SendUIWindow (send, _session);
                        send_ui->set_title (send->name());
-                       send->set_gui (send_ui);
+                       set_processor_ui (send, send_ui);
 
                } else {
-                       send_ui = reinterpret_cast<SendUIWindow *> (send->get_gui());
+                       send_ui = dynamic_cast<SendUIWindow *> (w);
                }
 
                gidget = send_ui;
@@ -1513,15 +1559,16 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
                boost::shared_ptr<Return> retrn = boost::dynamic_pointer_cast<Return> (processor);
 
                ReturnUIWindow *return_ui;
+               Window* w = get_processor_ui (retrn);
 
-               if (retrn->get_gui() == 0) {
+               if (w == 0) {
 
                        return_ui = new ReturnUIWindow (retrn, _session);
                        return_ui->set_title (retrn->name ());
-                       send->set_gui (return_ui);
+                       set_processor_ui (send, return_ui);
 
                } else {
-                       return_ui = reinterpret_cast<ReturnUIWindow *> (retrn->get_gui());
+                       return_ui = dynamic_cast<ReturnUIWindow *> (w);
                }
 
                gidget = return_ui;
@@ -1535,14 +1582,16 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
                Container* toplevel = get_toplevel();
                Window* win = dynamic_cast<Gtk::Window*>(toplevel);
 
-               if (plugin_insert->get_gui() == 0) {
+               Window* w = get_processor_ui (plugin_insert);
+
+               if (w == 0) {
 
                        plugin_ui = new PluginUIWindow (win, plugin_insert);
                        plugin_ui->set_title (generate_processor_title (plugin_insert));
-                       plugin_insert->set_gui (plugin_ui);
+                       set_processor_ui (plugin_insert, plugin_ui);
 
                } else {
-                       plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
+                       plugin_ui = dynamic_cast<PluginUIWindow *> (w);
                        plugin_ui->set_parent (win);
                }
 
@@ -1558,12 +1607,14 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
 
                PortInsertWindow *io_selector;
 
-               if (port_insert->get_gui() == 0) {
+               Window* w = get_processor_ui (port_insert);
+
+               if (w == 0) {
                        io_selector = new PortInsertWindow (_session, port_insert);
-                       port_insert->set_gui (io_selector);
+                       set_processor_ui (port_insert, io_selector);
 
                } else {
-                       io_selector = reinterpret_cast<PortInsertWindow *> (port_insert->get_gui());
+                       io_selector = dynamic_cast<PortInsertWindow *> (w);
                }
 
                gidget = io_selector;
@@ -1838,18 +1889,18 @@ ProcessorBox::route_property_changed (const PropertyChange& what_changed)
 
                processor = (*iter)->processor ();
 
-               void* gui = processor->get_gui();
+               Window* w = get_processor_ui (processor);
 
-               if (!gui) {
+               if (!w) {
                        continue;
                }
 
                /* rename editor windows for sends and plugins */
 
                if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
-                       static_cast<Window*>(gui)->set_title (send->name ());
+                       w->set_title (send->name ());
                } else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (processor)) != 0) {
-                       static_cast<Window*>(gui)->set_title (generate_processor_title (plugin_insert));
+                       w->set_title (generate_processor_title (plugin_insert));
                }
        }
 }
@@ -1882,3 +1933,75 @@ ProcessorBox::on_size_allocate (Allocation& a)
                (*i)->set_pixel_width (a.get_width ());
        }
 }
+
+/** @param p Processor.
+ *  @return the UI window for \a p.
+ */
+Window *
+ProcessorBox::get_processor_ui (boost::shared_ptr<Processor> p) const
+{
+       list<ProcessorWindowProxy*>::const_iterator i = _processor_window_proxies.begin ();
+       while (i != _processor_window_proxies.end()) {
+               boost::shared_ptr<Processor> t = (*i)->processor().lock ();
+               if (t && t == p) {
+                       return (*i)->get ();
+               }
+
+               ++i;
+       }
+
+       /* we shouldn't get here, because the ProcessorUIList should always contain
+          an entry for each processor.
+       */
+       assert (false);
+}
+
+/** Make a note of the UI window that a processor is using.
+ *  @param p Processor.
+ *  @param w UI window.
+ */
+void
+ProcessorBox::set_processor_ui (boost::shared_ptr<Processor> p, Gtk::Window* w)
+{
+       list<ProcessorWindowProxy*>::iterator i = _processor_window_proxies.begin ();
+       while (i != _processor_window_proxies.end()) {
+               boost::shared_ptr<Processor> t = (*i)->processor().lock ();
+               if (t && t == p) {
+                       (*i)->set (w);
+                       return;
+               }
+
+               ++i;
+       }
+
+       /* we shouldn't get here, because the ProcessorUIList should always contain
+          an entry for each processor.
+       */
+       assert (false);
+}
+
+ProcessorWindowProxy::ProcessorWindowProxy (
+       string const & name,
+       XMLNode const * node,
+       ProcessorBox* box,
+       boost::weak_ptr<Processor> processor
+       )
+       : WindowProxy<Gtk::Window> (name, node)
+       , marked (false)
+       , _processor_box (box)
+       , _processor (processor)
+{
+
+}
+
+
+void
+ProcessorWindowProxy::show ()
+{
+       boost::shared_ptr<Processor> p = _processor.lock ();
+       if (!p) {
+               return;
+       }
+
+       _processor_box->edit_processor (p);
+}
index 1e4257d22b16d207a2299dc8ed100b112ef40f55..9273a750521c044e51054c0b52c51341eaf83e27 100644 (file)
@@ -52,6 +52,7 @@
 #include "io_selector.h"
 #include "send_ui.h"
 #include "enums.h"
+#include "window_proxy.h"
 
 class MotionController;
 class PluginSelector;
@@ -71,6 +72,29 @@ namespace ARDOUR {
        class Session;
 }
 
+class ProcessorBox;
+
+/** A WindowProxy for Processor UI windows; it knows how to ask a ProcessorBox
+ *  to create a UI window for a particular processor.
+ */
+class ProcessorWindowProxy : public WindowProxy<Gtk::Window>
+{
+public:
+       ProcessorWindowProxy (std::string const &, XMLNode const *, ProcessorBox *, boost::weak_ptr<ARDOUR::Processor>);
+
+       void show ();
+
+       boost::weak_ptr<ARDOUR::Processor> processor () const {
+               return _processor;
+       }
+
+       bool marked;
+
+private:
+       ProcessorBox* _processor_box;
+       boost::weak_ptr<ARDOUR::Processor> _processor;
+};
+
 class ProcessorEntry : public Gtkmm2ext::DnDVBoxChild, public sigc::trackable
 {
 public:
@@ -145,12 +169,19 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
        void select_all_inserts ();
        void select_all_sends ();
 
+       Gtk::Window* get_processor_ui (boost::shared_ptr<ARDOUR::Processor>) const;
+       void edit_processor (boost::shared_ptr<ARDOUR::Processor>);
+       
        sigc::signal<void,boost::shared_ptr<ARDOUR::Processor> > ProcessorSelected;
        sigc::signal<void,boost::shared_ptr<ARDOUR::Processor> > ProcessorUnselected;
 
        static void register_actions();
 
   private:
+
+       /* prevent copy construction */
+       ProcessorBox (ProcessorBox const &);
+       
        boost::shared_ptr<ARDOUR::Route>  _route;
        MixerStrip*         _parent_strip; // null if in RouteParamsUI
        bool                _owner_is_mixer;
@@ -212,8 +243,6 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
        void reordered ();
        void route_processors_changed (ARDOUR::RouteProcessorChange);
 
-       void remove_processor_gui (boost::shared_ptr<ARDOUR::Processor>);
-
        void processors_reordered (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&, int*);
        void compute_processor_sort_keys ();
 
@@ -249,7 +278,6 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
 
        void activate_processor (boost::shared_ptr<ARDOUR::Processor>);
        void deactivate_processor (boost::shared_ptr<ARDOUR::Processor>);
-       void edit_processor (boost::shared_ptr<ARDOUR::Processor>);
        void hide_processor_editor (boost::shared_ptr<ARDOUR::Processor>);
        void rename_processor (boost::shared_ptr<ARDOUR::Processor>);
 
@@ -281,6 +309,10 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
 
        void route_property_changed (const PBD::PropertyChange&);
        std::string generate_processor_title (boost::shared_ptr<ARDOUR::PluginInsert> pi);
+
+       std::list<ProcessorWindowProxy*> _processor_window_proxies;
+       void set_processor_ui (boost::shared_ptr<ARDOUR::Processor>, Gtk::Window *);
+       void maybe_add_processor_to_ui_list (boost::weak_ptr<ARDOUR::Processor>);
 };
 
 #endif /* __ardour_gtk_processor_box__ */
index ea9ef9dfad8cb71b10e0229e711903d0e3ade581..6bf897bcd3f75f9227417f4a96ffe8eadc6e3e14 100644 (file)
@@ -274,7 +274,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible {
        virtual TimeAxisView* get_named_time_axis(const std::string & name)  = 0;
 #endif
 
-       virtual RouteTimeAxisView* get_route_view_by_id (PBD::ID& id) = 0;
+       virtual RouteTimeAxisView* get_route_view_by_route_id (PBD::ID& id) const = 0;
 
        virtual void get_equivalent_regions (RegionView* rv, std::vector<RegionView*>&, PBD::PropertyID) const = 0;
 
index e44c62949ba7ec2612a589b2b94413a3a2067776..c62ea68b2a211f49e90af9c0f4c8660a95fefe3d 100644 (file)
@@ -2275,7 +2275,7 @@ RouteTimeAxisView::set_underlay_state()
                if (prop) {
                        PBD::ID id (prop->value());
 
-                       RouteTimeAxisView* v = _editor.get_route_view_by_id (id);
+                       RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
 
                        if (v) {
                                add_underlay(v->view(), false);
index 786749ce727f00214d88dca3013939c247d61072..c9d12f0694d177ee40099804117f567ab9453755 100644 (file)
@@ -1075,3 +1075,68 @@ Selection::set_point_selection_from_line (AutomationLine const & line)
 
        PointsChanged (); /* EMIT SIGNAL */
 }
+
+XMLNode&
+Selection::get_state () const
+{
+       /* XXX: not complete; just sufficient to get track selection state
+          so that re-opening plugin windows for editor mixer strips works
+       */
+       
+       XMLNode* node = new XMLNode (X_("Selection"));
+
+       for (TrackSelection::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
+               AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (*i);
+               if (rtv) {
+                       XMLNode* t = node->add_child (X_("RouteView"));
+                       t->add_property (X_("id"), atoi (rtv->route()->id().to_s().c_str()));
+               } else if (atv) {
+                       XMLNode* t = node->add_child (X_("AutomationView"));
+                       t->add_property (X_("id"), atoi (atv->parent_route()->id().to_s().c_str()));
+                       t->add_property (X_("parameter"), EventTypeMap::instance().to_symbol (atv->control()->parameter ()));
+               }
+       }
+
+       return *node;
+}
+
+int
+Selection::set_state (XMLNode const & node, int)
+{
+       if (node.name() != X_("Selection")) {
+               return -1;
+       }
+       
+       XMLNodeList children = node.children ();
+       for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+               if ((*i)->name() == X_("RouteView")) {
+                       
+                       XMLProperty* prop_id = (*i)->property (X_("id"));
+                       assert (prop_id);
+                       PBD::ID id (prop_id->value ());
+                       RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
+                       assert (rtv);
+                       add (rtv);
+                       
+               } else if ((*i)->name() == X_("AutomationView")) {
+                       
+                       XMLProperty* prop_id = (*i)->property (X_("id"));
+                       XMLProperty* prop_parameter = (*i)->property (X_("parameter"));
+
+                       assert (prop_id);
+                       assert (prop_parameter);
+
+                       PBD::ID id (prop_id->value ());
+                       RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
+                       assert (rtv);
+                       
+                       boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().new_parameter (prop_parameter->value ()));
+                       assert (atv);
+                       
+                       add (atv.get());
+               }
+       }
+
+       return 0;
+}
index e81e1bdea8624460f0c345c884c5ae2db67b144c..81bb54b9df156b3f83e811b08c08abaf5851f568 100644 (file)
@@ -191,6 +191,9 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
        void foreach_midi_regionview (void (MidiRegionView::*method)(void));
        template<class A> void foreach_region (void (ARDOUR::Region::*method)(A), A arg);
 
+       XMLNode& get_state () const;
+       int set_state (XMLNode const &, int);
+
   private:
        void set_point_selection_from_line (AutomationLine const &);
 
diff --git a/gtk2_ardour/window_proxy.cc b/gtk2_ardour/window_proxy.cc
new file mode 100755 (executable)
index 0000000..28a9021
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+    Copyright (C) 2010 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <gtkmm/window.h>
+#include "window_proxy.h"
+
+using namespace std;
+
+/** WindowProxyBase constructor.
+ *  @param name Unique internal name for this window.
+ *  @param node <UI> node containing <Window> children, the appropriate one of which is used
+ *  to set up this object.
+ */
+WindowProxyBase::WindowProxyBase (string const & name, XMLNode const * node)
+       : _name (name)
+       , _visible (false)
+       , _x_off (-1)
+       , _y_off (-1)
+       , _width (-1)
+       , _height (-1)
+{
+       XMLNodeList children = node->children ();
+
+       XMLNodeList::const_iterator i = children.begin ();
+       while (i != children.end()) {
+               XMLProperty* prop = (*i)->property (X_("name"));
+               if ((*i)->name() == X_("Window") && prop && prop->value() == _name) {
+                       break;
+               }
+               
+               ++i;
+       }
+
+       if (i != children.end()) {
+
+               XMLProperty* prop;
+
+               if ((prop = (*i)->property (X_("visible"))) != 0) {
+                       _visible = string_is_affirmative (prop->value ());
+               }
+               
+               if ((prop = (*i)->property (X_("x-off"))) != 0) {
+                       _x_off = atoi (prop->value().c_str());
+               }
+               if ((prop = (*i)->property (X_("y-off"))) != 0) {
+                       _y_off = atoi (prop->value().c_str());
+               }
+               if ((prop = (*i)->property (X_("x-size"))) != 0) {
+                       _width = atoi (prop->value().c_str());
+               }
+               if ((prop = (*i)->property (X_("y-size"))) != 0) {
+                       _height = atoi (prop->value().c_str());
+               }
+       }
+}
+
+/** Show this window if it was configured as visible.  This should
+ *  be called at session startup only.
+ */
+void
+WindowProxyBase::maybe_show ()
+{
+       if (_visible) {
+               show ();
+               setup ();
+       }
+}
+
+/** Set up our window's position and size */
+void
+WindowProxyBase::setup ()
+{
+       Gtk::Window* window = get_gtk_window ();
+       if (!window) {
+               return;
+       }
+
+       if (_width != -1 && _height != -1) {
+               window->set_default_size (_width, _height);
+       }
+
+       if (_x_off != -1 && _y_off != -1) {
+               window->move (_x_off, _y_off);
+       }
+}
+
+XMLNode *
+WindowProxyBase::get_state () const
+{
+       bool v = _visible;
+       int x = _x_off;
+       int y = _y_off;
+       int w = _width;
+       int h = _height;
+
+       /* If the window has been created, get its current state; otherwise use
+          the state that we started off with.
+       */
+       
+       Gtk::Window* gtk_window = get_gtk_window ();
+       if (gtk_window) {
+               v = gtk_window->is_visible ();
+
+               Glib::RefPtr<Gdk::Window> gdk_window = gtk_window->get_window ();
+               if (gdk_window) {
+                       gdk_window->get_position (x, y);
+                       gdk_window->get_size (w, h);
+               }
+
+       }
+
+       return state_node (v, x, y, w, h);
+}
+
+
+XMLNode *
+WindowProxyBase::state_node (bool v, int x, int y, int w, int h) const
+{
+       XMLNode* node = new XMLNode (X_("Window"));
+       node->add_property (X_("name"), _name);
+       node->add_property (X_("visible"), v ? X_("yes") : X_("no"));
+
+       char buf[32];
+       snprintf (buf, sizeof (buf), "%d", x);
+       node->add_property (X_("x-off"), buf);
+       snprintf (buf, sizeof (buf), "%d", y);
+       node->add_property (X_("y-off"), buf);
+       snprintf (buf, sizeof (buf), "%d", w);
+       node->add_property (X_("x-size"), buf);
+       snprintf (buf, sizeof (buf), "%d", h);
+       node->add_property (X_("y-size"), buf);
+
+       return node;
+}
diff --git a/gtk2_ardour/window_proxy.h b/gtk2_ardour/window_proxy.h
new file mode 100755 (executable)
index 0000000..e2b015c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+    Copyright (C) 2010 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_window_proxy_h__
+#define __ardour_window_proxy_h__
+
+#include <gtkmm/action.h>
+#include <gtkmm/toggleaction.h>
+#include "actions.h"
+
+class XMLNode;
+
+/** A class to proxy for a window that may not have been created yet.
+ *  It allows the management of visibility, position and size state
+ *  so that it can be saved and restored across session loads.
+ *
+ *  Subclasses of WindowProxy handle windows that are created in different
+ *  ways.
+ */
+class WindowProxyBase
+{
+public:
+       WindowProxyBase (std::string const &, XMLNode const *);
+       virtual ~WindowProxyBase () {}
+
+       std::string name () const {
+               return _name;
+       }
+       
+       void maybe_show ();
+       XMLNode* get_state () const;
+       void setup ();
+
+       /** Show this window */
+       virtual void show () = 0;
+
+       virtual Gtk::Window* get_gtk_window () const = 0;
+
+private:
+       XMLNode* state_node (bool, int, int, int, int) const;
+       
+       std::string _name; ///< internal unique name for this window
+       bool _visible; ///< true if the window should be visible on startup
+       int _x_off; ///< x position
+       int _y_off; ///< y position 
+       int _width; ///< width
+       int _height; ///< height
+};
+
+/** Templated WindowProxy which contains a pointer to the window that is proxying for */
+template <class T>
+class WindowProxy : public WindowProxyBase
+{
+public:
+       WindowProxy (std::string const & name, XMLNode const * node)
+               : WindowProxyBase (name, node)
+               , _window (0)
+       {
+               
+       }
+
+       Gtk::Window* get_gtk_window () const {
+               return _window;
+       }
+
+       T* get () const {
+               return _window;
+       }
+
+       /** Set the window and set it up.  To be used after initial window creation */
+       void set (T* w) {
+               _window = w;
+               setup ();
+       }
+
+private:
+       T* _window;
+};
+
+/** WindowProxy for windows that are created in response to a GTK Action being set active.
+ *  Templated on the type of the window.
+ */
+template <class T>
+class ActionWindowProxy : public WindowProxy<T>
+{
+public:
+       /** ActionWindowProxy constructor.
+        *  @param name Unique internal name for this window.
+        *  @param node <UI> node containing <Window> children, the appropriate one of which is used
+        *  to set up this object.
+        *  @param action Name of the ToggleAction that controls this window's visibility.
+        */
+       ActionWindowProxy (std::string const & name, XMLNode const * node, std::string const & action)
+               : WindowProxy<T> (name, node)
+               , _action (action)
+       {
+               
+       }
+
+       void show () {
+               /* Set the appropriate action active so that the window gets shown */
+               Glib::RefPtr<Gtk::Action> act = ActionManager::get_action ("Common", _action.c_str());
+               if (act) {
+                       Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic (act);
+                       assert (tact);
+                       tact->set_active (true);
+               }
+       }
+
+private:
+       std::string _action;
+};
+
+#endif
index d87e31a604922136e0cb7a10c4714e89f48fcdaf..4b24082d47f8b95050661a516a5356c4513e9710 100644 (file)
@@ -209,6 +209,7 @@ gtk2_ardour_sources = [
        'version.cc',
         'volume_controller.cc',
        'waveview.cc',
+       'window_proxy.cc'
 ]
 
 def set_options(opt):
index e95bd57adf6bcf269d29bf9627061dd8958e1f79..1e65bc58bd5f6225fe22a5375b57ddc17412fe79 100644 (file)
@@ -95,9 +95,6 @@ class Processor : public SessionObject, public Automatable, public Latent
        XMLNode& get_state (void);
        int set_state (const XMLNode&, int version);
        
-       void *get_gui () const { return _gui; }
-       void  set_gui (void *p) { _gui = p; }
-
        void set_pre_fader (bool);
 
        PBD::Signal0<void>                     ActiveChanged;
@@ -110,7 +107,6 @@ protected:
        bool      _configured;
        ChanCount _configured_input;
        ChanCount _configured_output;
-       void*     _gui;  /* generic, we don't know or care what this is */
        bool      _display_to_user;
        bool      _pre_fader;
 
index c75a7720e0b8c3512a7d107cd3e25fb5dfd42b62..0bea376fc93630888307dfa6faf6b5ea9226fdb9 100644 (file)
@@ -66,7 +66,6 @@ Processor::Processor(Session& session, const string& name)
        , _active(false)
        , _next_ab_is_active(false)
        , _configured(false)
-       , _gui(0)
        , _display_to_user (true)
        , _pre_fader (false)
 {