From 579fcb70e2b3b0a1ef2af9fc88edebff6d7e6dd3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 18 Aug 2010 02:20:15 +0000 Subject: [PATCH] First go at saving window visibility and position state across saves. git-svn-id: svn://localhost/ardour2/branches/3.0@7644 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour_ui.cc | 95 ++++++++----- gtk2_ardour/ardour_ui.h | 19 ++- gtk2_ardour/ardour_ui2.cc | 3 +- gtk2_ardour/ardour_ui_dialogs.cc | 29 ++-- gtk2_ardour/ardour_ui_ed.cc | 119 ++++++---------- gtk2_ardour/automation_time_axis.h | 4 + gtk2_ardour/editor.cc | 34 ++--- gtk2_ardour/editor.h | 6 +- gtk2_ardour/editor_actions.cc | 4 - gtk2_ardour/mixer_strip.cc | 13 +- gtk2_ardour/mixer_strip.h | 4 + gtk2_ardour/processor_box.cc | 217 ++++++++++++++++++++++------- gtk2_ardour/processor_box.h | 38 ++++- gtk2_ardour/public_editor.h | 2 +- gtk2_ardour/route_time_axis.cc | 2 +- gtk2_ardour/selection.cc | 65 +++++++++ gtk2_ardour/selection.h | 3 + gtk2_ardour/window_proxy.cc | 150 ++++++++++++++++++++ gtk2_ardour/window_proxy.h | 131 +++++++++++++++++ gtk2_ardour/wscript | 1 + libs/ardour/ardour/processor.h | 4 - libs/ardour/processor.cc | 1 - 22 files changed, 715 insertions(+), 229 deletions(-) create mode 100755 gtk2_ardour/window_proxy.cc create mode 100755 gtk2_ardour/window_proxy.h diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index f1120ccfca..837dfd9ba2 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -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 (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations")); + big_clock_window = new ActionWindowProxy (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 ( + 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 act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock")); - if (act) { - Glib::RefPtr tact = Glib::RefPtr::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); +} diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index cccc4ab5b0..bf9a88d29e 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -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* 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* location_ui; int create_location_ui (); void handle_locations_change (ARDOUR::Location*); + ActionWindowProxy* _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 _window_proxies; }; #endif /* __ardour_gui_h__ */ diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc index 62b827d61a..65f165aa6e 100644 --- a/gtk2_ardour/ardour_ui2.cc +++ b/gtk2_ardour/ardour_ui2.cc @@ -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 (); diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc index 747354ca4e..6a0bbb0a7e 100644 --- a/gtk2_ardour/ardour_ui_dialogs.cc +++ b/gtk2_ardour/ardour_ui_dialogs.cc @@ -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 tact = RefPtr::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_("/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_("/Common/ToggleLocations"))); } return 0; } @@ -316,10 +323,10 @@ ARDOUR_UI::toggle_location_window () RefPtr tact = RefPtr::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 (); } } } diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index efdbd13add..091d846c1b 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -47,6 +47,8 @@ #include "mixer_ui.h" #include "startup.h" #include "utils.h" +#include "window_proxy.h" +#include "global_port_matrix.h" #include @@ -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_("/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_("/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 win = big_clock_window->get_window(); + Glib::RefPtr 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")); + + for (list::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) { + window_node->add_child_nocopy (*((*i)->get_state ())); + } - window_node->add_property ("show-big-clock", (big_clock_window && big_clock_window->is_visible() ? "yes" : "no")); - - Glib::RefPtr 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); - } - /* 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 (); + } +} + diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 8daccf97eb..c4132269f1 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -107,6 +107,10 @@ class AutomationTimeAxisView : public TimeAxisView { bool has_automation () const; + boost::shared_ptr parent_route () { + return _route; + } + protected: boost::shared_ptr _route; ///< Parent route boost::shared_ptr _control; ///< Control diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 097a7cf418..adfbf5293a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -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 (_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 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(*i)) != 0) { if(v->route()->id() == id) { return v; diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 45ef788d40..22f68c23ce 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -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 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); void hide_a_region (boost::shared_ptr); @@ -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 (); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 8c70c4d148..e8eeb4d572 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -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); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index ecd1b733be..4523ca524a 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -362,6 +362,8 @@ MixerStrip::set_route (boost::shared_ptr 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 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 p) return; } - void* gui = processor->get_gui (); + Gtk::Window* w = processor_box.get_processor_ui (processor); - if (gui) { - static_cast(gui)->hide (); + if (w) { + w->hide (); } } diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index 0d3878fc20..bbebbcaf15 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -99,6 +99,10 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void set_button_names (); void show_send (boost::shared_ptr); + bool mixer_owned () const { + return _mixer_owned; + } + sigc::signal WidthChanged; static sigc::signal > SwitchIO; diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index cc322df13d..8840c773f9 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -392,28 +392,6 @@ ProcessorBox::set_width (Width w) redisplay_processors (); } -void -ProcessorBox::remove_processor_gui (boost::shared_ptr processor) -{ - boost::shared_ptr send; - boost::shared_ptr retrn; - boost::shared_ptr port_insert; - - if ((port_insert = boost::dynamic_pointer_cast (processor)) != 0) { - PortInsertUI *io_selector = reinterpret_cast (port_insert->get_gui()); - port_insert->set_gui (0); - delete io_selector; - } else if ((send = boost::dynamic_pointer_cast (processor)) != 0) { - SendUIWindow *sui = reinterpret_cast (send->get_gui()); - send->set_gui (0); - delete sui; - } else if ((retrn = boost::dynamic_pointer_cast (processor)) != 0) { - ReturnUIWindow *rui = reinterpret_cast (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::iterator i = _processor_window_proxies.begin(); + while (i != _processor_window_proxies.end()) { + list::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 w) +{ + boost::shared_ptr p = w.lock (); + if (!p) { + return; + } + + list::iterator i = _processor_window_proxies.begin (); + while (i != _processor_window_proxies.end()) { + + boost::shared_ptr 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((*i)) != 0) || (boost::dynamic_pointer_cast((*i)) != 0)) { - void* gui = (*i)->get_gui (); + Window* w = get_processor_ui (*i); - if (gui) { - static_cast(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(gui)->hide (); + if (w) { + w->hide (); } _route->remove_processor(*i); @@ -1195,10 +1240,10 @@ ProcessorBox::delete_dragged_processors (const list 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(gui)->hide (); + if (w) { + w->hide (); } _route->remove_processor(*x); @@ -1488,13 +1533,14 @@ ProcessorBox::edit_processor (boost::shared_ptr 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 (send->get_gui()); + send_ui = dynamic_cast (w); } gidget = send_ui; @@ -1513,15 +1559,16 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) boost::shared_ptr retrn = boost::dynamic_pointer_cast (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 (retrn->get_gui()); + return_ui = dynamic_cast (w); } gidget = return_ui; @@ -1535,14 +1582,16 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) Container* toplevel = get_toplevel(); Window* win = dynamic_cast(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 (plugin_insert->get_gui()); + plugin_ui = dynamic_cast (w); plugin_ui->set_parent (win); } @@ -1558,12 +1607,14 @@ ProcessorBox::edit_processor (boost::shared_ptr 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 (port_insert->get_gui()); + io_selector = dynamic_cast (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 (processor)) != 0) { - static_cast(gui)->set_title (send->name ()); + w->set_title (send->name ()); } else if ((plugin_insert = boost::dynamic_pointer_cast (processor)) != 0) { - static_cast(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 p) const +{ + list::const_iterator i = _processor_window_proxies.begin (); + while (i != _processor_window_proxies.end()) { + boost::shared_ptr 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 p, Gtk::Window* w) +{ + list::iterator i = _processor_window_proxies.begin (); + while (i != _processor_window_proxies.end()) { + boost::shared_ptr 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 + ) + : WindowProxy (name, node) + , marked (false) + , _processor_box (box) + , _processor (processor) +{ + +} + + +void +ProcessorWindowProxy::show () +{ + boost::shared_ptr p = _processor.lock (); + if (!p) { + return; + } + + _processor_box->edit_processor (p); +} diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h index 1e4257d22b..9273a75052 100644 --- a/gtk2_ardour/processor_box.h +++ b/gtk2_ardour/processor_box.h @@ -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 +{ +public: + ProcessorWindowProxy (std::string const &, XMLNode const *, ProcessorBox *, boost::weak_ptr); + + void show (); + + boost::weak_ptr processor () const { + return _processor; + } + + bool marked; + +private: + ProcessorBox* _processor_box; + boost::weak_ptr _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) const; + void edit_processor (boost::shared_ptr); + sigc::signal > ProcessorSelected; sigc::signal > ProcessorUnselected; static void register_actions(); private: + + /* prevent copy construction */ + ProcessorBox (ProcessorBox const &); + boost::shared_ptr _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); - 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); void deactivate_processor (boost::shared_ptr); - void edit_processor (boost::shared_ptr); void hide_processor_editor (boost::shared_ptr); void rename_processor (boost::shared_ptr); @@ -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 pi); + + std::list _processor_window_proxies; + void set_processor_ui (boost::shared_ptr, Gtk::Window *); + void maybe_add_processor_to_ui_list (boost::weak_ptr); }; #endif /* __ardour_gtk_processor_box__ */ diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index ea9ef9dfad..6bf897bcd3 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -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&, PBD::PropertyID) const = 0; diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index e44c62949b..c62ea68b2a 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -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); diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 786749ce72..c9d12f0694 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -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 (*i); + AutomationTimeAxisView* atv = dynamic_cast (*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 atv = rtv->automation_child (EventTypeMap::instance().new_parameter (prop_parameter->value ())); + assert (atv); + + add (atv.get()); + } + } + + return 0; +} diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index e81e1bdea8..81bb54b9df 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -191,6 +191,9 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList void foreach_midi_regionview (void (MidiRegionView::*method)(void)); template 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 index 0000000000..28a90215af --- /dev/null +++ b/gtk2_ardour/window_proxy.cc @@ -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 +#include "window_proxy.h" + +using namespace std; + +/** WindowProxyBase constructor. + * @param name Unique internal name for this window. + * @param node node containing 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 = 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 index 0000000000..e2b015c27b --- /dev/null +++ b/gtk2_ardour/window_proxy.h @@ -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 +#include +#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 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 ActionWindowProxy : public WindowProxy +{ +public: + /** ActionWindowProxy constructor. + * @param name Unique internal name for this window. + * @param node node containing 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 (name, node) + , _action (action) + { + + } + + void show () { + /* Set the appropriate action active so that the window gets shown */ + Glib::RefPtr act = ActionManager::get_action ("Common", _action.c_str()); + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); + assert (tact); + tact->set_active (true); + } + } + +private: + std::string _action; +}; + +#endif diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index d87e31a604..4b24082d47 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -209,6 +209,7 @@ gtk2_ardour_sources = [ 'version.cc', 'volume_controller.cc', 'waveview.cc', + 'window_proxy.cc' ] def set_options(opt): diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index e95bd57adf..1e65bc58bd 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -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 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; diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index c75a7720e0..0bea376fc9 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -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) {