#include <sys/resource.h>
#endif
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
#include <stdint.h>
#include <fcntl.h>
#include <signal.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/accelmap.h>
+#include <gtkmm/stock.h>
#include "pbd/error.h"
#include "pbd/basename.h"
#include "pbd/compose.h"
#include "pbd/convert.h"
#include "pbd/failed_constructor.h"
+#include "pbd/file_archive.h"
#include "pbd/enumwriter.h"
#include "pbd/memento_command.h"
#include "pbd/openuri.h"
#include "ardour/process_thread.h"
#include "ardour/profile.h"
#include "ardour/recent_sessions.h"
+#include "ardour/record_enable_control.h"
#include "ardour/session_directory.h"
#include "ardour/session_route.h"
#include "ardour/session_state_utils.h"
#include "route_params_ui.h"
#include "save_as_dialog.h"
#include "script_selector.h"
+#include "session_archive_dialog.h"
#include "session_dialog.h"
#include "session_metadata_dialog.h"
#include "session_option_editor.h"
-#include "shuttle_control.h"
#include "speaker_dialog.h"
#include "splash.h"
#include "startup.h"
#include "theme_manager.h"
#include "time_axis_view_item.h"
+#include "time_info_box.h"
#include "timers.h"
#include "utils.h"
#include "video_server_dialog.h"
#include "add_video_dialog.h"
#include "transcode_video_dialog.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
using namespace ARDOUR;
using namespace ARDOUR_UI_UTILS;
, _mixer_on_top (false)
, _initial_verbose_plugin_scan (false)
, first_time_engine_run (true)
+ , secondary_clock_spacer (0)
, roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
, stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
, goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
, auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
, play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
, rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
+ , time_info_box (0)
, auto_return_button (ArdourButton::led_default_elements)
, follow_edits_button (ArdourButton::led_default_elements)
, auto_input_button (ArdourButton::led_default_elements)
, speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
, add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
, about (X_("about"), _("About"))
- , location_ui (X_("locations"), _("Locations"))
+ , location_ui (X_("locations"), S_("Ranges|Locations"))
, route_params (X_("inspector"), _("Tracks and Busses"))
, audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
, export_video_dialog (X_("video-export"), _("Video Export Dialog"))
_exit (0);
}
+
+ if (string (VERSIONSTRING).find (".pre") != string::npos) {
+ /* check this is not being run from ./ardev etc. */
+ if (!running_from_source_tree ()) {
+ pre_release_dialog ();
+ }
+ }
+
if (theArdourUI == 0) {
theArdourUI = this;
}
WM::Manager::instance().register_window (&audio_port_matrix);
WM::Manager::instance().register_window (&midi_port_matrix);
+ /* do not retain position for add route dialog */
+ add_route_dialog.set_state_mask (WindowProxy::Size);
+
/* Trigger setting up the color scheme and loading the GTK RC file */
UIConfiguration::instance().load_rc_file (false);
attach_to_engine ();
}
+void
+ARDOUR_UI::pre_release_dialog ()
+{
+ ArdourDialog d (_("Pre-Release Warning"), true, false);
+ d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+ Label* label = manage (new Label);
+ label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
+There are still several issues and bugs to be worked on,\n\
+as well as general workflow improvements, before this can be considered\n\
+release software. So, a few guidelines:\n\
+\n\
+1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
+ though it may be so, depending on your workflow.\n\
+2) Please wait for a helpful writeup of new features.\n\
+3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
+4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
+ making sure to note the product version number as 5.0-pre.\n\
+5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
+6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
+ can get there directly from within the program via the Help->Chat menu option.\n\
+\n\
+Full information on all the above can be found on the support page at\n\
+\n\
+ http://ardour.org/support\n\
+"), PROGRAM_NAME, VERSIONSTRING));
+
+ d.get_vbox()->set_border_width (12);
+ d.get_vbox()->pack_start (*label, false, false, 12);
+ d.get_vbox()->show_all ();
+
+ d.run ();
+}
+
GlobalPortMatrixWindow*
ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
{
delete primary_clock; primary_clock = 0;
delete secondary_clock; secondary_clock = 0;
delete _process_thread; _process_thread = 0;
+ delete time_info_box; time_info_box = 0;
delete meterbridge; meterbridge = 0;
delete luawindow; luawindow = 0;
delete editor; editor = 0;
rec_controllable->set_id (prop->value());
}
if ((prop = node.property ("shuttle")) != 0) {
- shuttle_box->controllable()->set_id (prop->value());
+ shuttle_box.controllable()->set_id (prop->value());
}
}
node->add_property (X_("play_selection"), buf);
rec_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("rec"), buf);
- shuttle_box->controllable()->id().print (buf, sizeof (buf));
+ shuttle_box.controllable()->id().print (buf, sizeof (buf));
node->add_property (X_("shuttle"), buf);
return *node;
}
}
+ // TODO: maybe IFF brand_new_user
+ if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
+ std::string dspd (Config->get_default_session_parent_dir());
+ Searchpath ds (ARDOUR::ardour_data_search_path());
+ ds.add_subdirectory_to_paths ("sessions");
+ vector<string> demos;
+ find_files_matching_pattern (demos, ds, "*.tar.xz");
+
+ ARDOUR::RecentSessions rs;
+ ARDOUR::read_recent_sessions (rs);
+
+ for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
+ /* "demo-session" must be inside "demo-session.tar.xz"
+ * strip ".tar.xz"
+ */
+ std::string name = basename_nosuffix (basename_nosuffix (*i));
+ std::string path = Glib::build_filename (dspd, name);
+ /* skip if session-dir already exists */
+ if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
+ continue;
+ }
+ /* skip sessions that are already in 'recent'.
+ * eg. a new user changed <session-default-dir> shorly after installation
+ */
+ for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
+ if ((*r).first == name) {
+ continue;
+ }
+ }
+ try {
+ PBD::FileArchive ar (*i);
+ if (0 == ar.inflate (dspd)) {
+ store_recent_sessions (name, path);
+ info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
+ }
+ } catch (...) {}
+ }
+ }
+
#ifdef NO_PLUGIN_STATE
ARDOUR::RecentSessions rs;
*/
save_ardour_state ();
+ if (key_editor.get (false)) {
+ key_editor->disconnect ();
+ }
+
close_all_dialogs ();
if (_session) {
{
// august 2007: actual update frequency: 25Hz (40ms), not 100Hz
- if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
+ if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
float mpeak = editor_meter->update_meters();
if (mpeak > editor_meter_max_peak) {
if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
const string& name_template,
bool strict_io,
PluginInfoPtr instrument,
- Plugin::PresetRecord* pset)
+ Plugin::PresetRecord* pset,
+ ARDOUR::PresentationInfo::order_t order)
{
list<boost::shared_ptr<MidiTrack> > tracks;
}
try {
- tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
+ tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
if (tracks.size() != how_many) {
error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
const string& name_template,
bool strict_io,
PluginInfoPtr instrument,
- Plugin::PresetRecord* pset)
+ Plugin::PresetRecord* pset,
+ ARDOUR::PresentationInfo::order_t order)
{
RouteList routes;
}
try {
- routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
+
+ routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
if (routes.size() != how_many) {
error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
}
const string& name_template,
bool strict_io,
PluginInfoPtr instrument,
- Plugin::PresetRecord* pset)
+ Plugin::PresetRecord* pset,
+ ARDOUR::PresentationInfo::order_t order)
{
ChanCount one_midi_channel;
one_midi_channel.set (DataType::MIDI, 1);
if (disk) {
- session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
+ session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
} else {
- session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
+ session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
}
}
RouteGroup* route_group,
uint32_t how_many,
string const & name_template,
- bool strict_io
- )
+ bool strict_io,
+ ARDOUR::PresentationInfo::order_t order)
{
list<boost::shared_ptr<AudioTrack> > tracks;
RouteList routes;
try {
if (track) {
- tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
+ tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
if (tracks.size() != how_many) {
error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
} else {
- routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
+ routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
if (routes.size() != how_many) {
error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
}
if (none_record_enabled) {
- _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), 1.0, Controllable::NoGroup);
+ _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
}
return none_record_enabled;
if (affect_transport) {
if (rolling) {
_session->request_stop (with_abort, true);
- } else {
+
+ } else if (!with_abort) { /* with_abort == true means the
+ * command was intended to stop
+ * transport, not start.
+ */
+
/* the only external sync condition we can be in here
* would be Engine (JACK) sync, in which case we still
* want to do this.
}
void
-ARDOUR_UI::toggle_record_enable (uint32_t rid)
+ARDOUR_UI::toggle_record_enable (uint16_t rid)
{
if (!_session) {
return;
boost::shared_ptr<Route> r;
- if ((r = _session->route_by_remote_id (rid)) != 0) {
+ if ((r = _session->get_remote_nth_route (rid)) != 0) {
boost::shared_ptr<Track> t;
play_selection_button.unset_active_state ();
roll_button.unset_active_state ();
stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ layered_button.set_sensitive (false);
return;
}
- shuttle_box->map_transport_state ();
+ shuttle_box.map_transport_state ();
float sp = _session->transport_speed();
roll_button.set_active (true);
play_selection_button.set_active (true);
}
+ layered_button.set_sensitive (!_session->actively_recording ());
stop_button.set_active (false);
} else {
+ layered_button.set_sensitive (true);
stop_button.set_active (true);
roll_button.set_active (false);
play_selection_button.set_active (false);
}
}
+void
+ARDOUR_UI::archive_session ()
+{
+ if (!_session) {
+ return;
+ }
+
+ time_t n;
+ time (&n);
+ Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
+
+ SessionArchiveDialog sad;
+ sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
+ int response = sad.run ();
+
+ if (response != Gtk::RESPONSE_OK) {
+ sad.hide ();
+ return;
+ }
+
+ if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
+ MessageDialog msg (_("Session Archiving failed."));
+ msg.run ();
+ }
+}
+
void
ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
{
if (switch_to_it) {
prompter.set_initial_text (_session->snap_name());
} else {
- char timebuf[128];
- time_t n;
- struct tm local_time;
-
- time (&n);
- localtime_r (&n, &local_time);
- strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
- prompter.set_initial_text (timebuf);
+ Glib::DateTime tm (g_date_time_new_now_local ());
+ prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
}
bool finished = false;
void
ARDOUR_UI::load_from_application_api (const std::string& path)
{
+ /* OS X El Capitan (and probably later) now somehow passes the command
+ line arguments to an app via the openFile delegate protocol. Ardour
+ already does its own command line processing, and having both
+ pathways active causes crashes. So, if the command line was already
+ set, do nothing here.
+ */
+
+ if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
+ return;
+ }
+
ARDOUR_COMMAND_LINE::session_name = path;
+
/* Cancel SessionDialog if it's visible to make OSX delegates work.
*
* ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
{
Timers::TimerSuspender t;
- flush_pending ();
+ flush_pending (10);
}
#ifdef WINDOWS_VST_SUPPORT
}
catch (SessionException e) {
+ cerr << "Here are the errors associated with this failed session:\n";
dump_errors (cerr);
+ cerr << "---------\n";
MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
msg.set_title (_("Loading Error"));
msg.set_position (Gtk::WIN_POS_CENTER);
return -1;
}
catch (...) {
+ cerr << "Here are the errors associated with this failed session:\n";
dump_errors (cerr);
+ cerr << "---------\n";
MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
msg.set_title (_("Loading Error"));
msg.set_position (Gtk::WIN_POS_CENTER);
new_session->add_instant_xml (*n, false);
}
+ n = Config->instant_xml (X_("Preferences"));
+ if (n) {
+ new_session->add_instant_xml (*n, false);
+ }
+
/* Put the playhead at 0 and scroll fully left */
n = new_session->instant_xml (X_("Editor"));
if (n) {
}
}
-void
-ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
+PresentationInfo::order_t
+ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
{
- uint32_t order_hint = UINT32_MAX;
-
if (editor->get_selection().tracks.empty()) {
- return;
+ return PresentationInfo::max_order;
}
+ PresentationInfo::order_t order_hint = PresentationInfo::max_order;
+
/*
we want the new routes to have their order keys set starting from
the highest order key in the selection + 1 (if available).
*/
- if (place == AddRouteDialog::AfterSelection) {
+ if (place == RouteDialogs::AfterSelection) {
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
if (rtav) {
- order_hint = rtav->route()->order_key();
+ order_hint = rtav->route()->presentation_info().order();
order_hint++;
}
- } else if (place == AddRouteDialog::BeforeSelection) {
+ } else if (place == RouteDialogs::BeforeSelection) {
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
if (rtav) {
- order_hint = rtav->route()->order_key();
+ order_hint = rtav->route()->presentation_info().order();
}
- } else if (place == AddRouteDialog::First) {
+ } else if (place == RouteDialogs::First) {
order_hint = 0;
} else {
- /* leave order_hint at UINT32_MAX */
- }
-
- if (order_hint == UINT32_MAX) {
- /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
- * not setting an order hint will place new routes last.
- */
- return;
+ /* leave order_hint at max_order */
}
- _session->set_order_hint (order_hint);
-
- /* create a gap in the existing route order keys to accomodate new routes.*/
- boost::shared_ptr <RouteList> rd = _session->get_routes();
- for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
- boost::shared_ptr<Route> rt (*ri);
-
- if (rt->is_monitor()) {
- continue;
- }
-
- if (rt->order_key () >= order_hint) {
- rt->set_order_key (rt->order_key () + add_route_dialog->count());
- }
- }
+ return order_hint;
}
void
void
ARDOUR_UI::add_route ()
{
- int count;
+ if (!add_route_dialog.get (false)) {
+ add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
+ }
if (!_session) {
return;
return;
}
- ResponseType r = (ResponseType) add_route_dialog->run ();
+ add_route_dialog->set_position (WIN_POS_MOUSE);
+ add_route_dialog->present();
+}
+
+void
+ARDOUR_UI::add_route_dialog_finished (int r)
+{
+ int count;
add_route_dialog->hide();
return;
}
- setup_order_hint(add_route_dialog->insert_at());
+ PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
string template_path = add_route_dialog->track_template();
DisplaySuspender ds;
if (!template_path.empty()) {
if (add_route_dialog->name_template_is_default()) {
- _session->new_route_from_template (count, template_path, string());
+ _session->new_route_from_template (count, order, template_path, string());
} else {
- _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
+ _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
}
return;
}
/* XXX do something with name template */
+ Session::ProcessorChangeBlocker pcb (_session);
+
switch (add_route_dialog->type_wanted()) {
case AddRouteDialog::AudioTrack:
- session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
+ session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
break;
case AddRouteDialog::MidiTrack:
- session_add_midi_track (route_group, count, name_template, strict_io, instrument);
+ session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
break;
case AddRouteDialog::MixedTrack:
- session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
+ session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
break;
case AddRouteDialog::AudioBus:
- session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
+ session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
break;
case AddRouteDialog::MidiBus:
- session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
+ session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
break;
case AddRouteDialog::VCAMaster:
session_add_vca (name_template, count);
export_video_dialog->hide ();
}
+XMLNode*
+ARDOUR_UI::preferences_settings () const
+{
+ XMLNode* node = 0;
+
+ if (_session) {
+ node = _session->instant_xml(X_("Preferences"));
+ } else {
+ node = Config->instant_xml(X_("Preferences"));
+ }
+
+ if (!node) {
+ node = new XMLNode (X_("Preferences"));
+ }
+
+ return node;
+}
+
XMLNode*
ARDOUR_UI::mixer_settings () const
{
{
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
- if (!_session || !big_clock_window) {
+ if (!_session) {
/* why bother - the clock isn't visible */
return;
}
- if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
- big_clock->set_active (true);
- } else {
- big_clock->set_active (false);
+ ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
+
+ if (big_clock_window) {
+ if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
+ big_clock->set_active (true);
+ } else {
+ big_clock->set_active (false);
+ }
}
+
}
bool
MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
"%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
- "From now on, use the -2000 version with older versions of %3"),
+ "From now on, use the backup copy with older versions of %3"),
xml_path, backup_path, PROGRAM_NAME,
start_big, end_big,
start_mono, end_mono), true);
while (true) {
int response = audio_midi_setup->run();
+ printf("RESPONSE %d\n", response);
switch (response) {
- case Gtk::RESPONSE_OK:
+ case Gtk::RESPONSE_DELETE_EVENT:
+ return -1;
+ default:
if (!AudioEngine::instance()->running()) {
continue;
- } else {
- return 0;
}
+ audio_midi_setup->hide ();
return 0;
- default:
- return -1;
}
}
}
if (window_icons.empty()) {
Glib::RefPtr<Gdk::Pixbuf> icon;
- if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
+ if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
window_icons.push_back (icon);
}
- if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
+ if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
window_icons.push_back (icon);
}
- if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
+ if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
window_icons.push_back (icon);
}
- if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
+ if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
window_icons.push_back (icon);
}
}
}
static Gtkmm2ext::Bindings*
-get_bindings_from_widget_heirarchy (GtkWidget* w)
+get_bindings_from_widget_heirarchy (GtkWidget** w)
{
void* p = NULL;
- while (w) {
- if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
+ while (*w) {
+ if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
break;
}
- w = gtk_widget_get_parent (w);
+ *w = gtk_widget_get_parent (*w);
}
return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
{
GtkWindow* win = window.gobj();
GtkWidget* focus = gtk_window_get_focus (win);
+ GtkWidget* binding_widget = focus;
bool special_handling_of_unmodified_accelerators = false;
const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
} else {
- Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
+ Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
if (focus_bindings) {
bindings = focus_bindings;
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
win,
ev->keyval,
- show_gdk_event_state (ev->state),
+ Gtkmm2ext::show_gdk_event_state (ev->state),
special_handling_of_unmodified_accelerators,
Keyboard::some_magic_widget_has_focus(),
focus,
DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
KeyboardKey k (ev->state, ev->keyval);
- if (bindings) {
+ while (bindings) {
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
return true;
}
+
+ if (binding_widget) {
+ binding_widget = gtk_widget_get_parent (binding_widget);
+ if (binding_widget) {
+ bindings = get_bindings_from_widget_heirarchy (&binding_widget);
+ } else {
+ bindings = 0;
+ }
+ } else {
+ bindings = 0;
+ }
}
DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
KeyboardKey k (ev->state, ev->keyval);
- if (bindings) {
+ while (bindings) {
DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
return true;
}
+ if (binding_widget) {
+ binding_widget = gtk_widget_get_parent (binding_widget);
+ if (binding_widget) {
+ bindings = get_bindings_from_widget_heirarchy (&binding_widget);
+ } else {
+ bindings = 0;
+ }
+ } else {
+ bindings = 0;
+ }
}
DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
ARDOUR_UI::cancel_solo ()
{
if (_session) {
- _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
+ _session->cancel_all_solo ();
+ }
+}
+
+void
+ARDOUR_UI::reset_focus (Gtk::Widget* w)
+{
+ /* this resets focus to the first focusable parent of the given widget,
+ * or, if there is no focusable parent, cancels focus in the toplevel
+ * window that the given widget is packed into (if there is one).
+ */
+
+ if (!w) {
+ return;
+ }
+
+ Gtk::Widget* top = w->get_toplevel();
+
+ if (!top || !top->is_toplevel()) {
+ return;
}
+
+ w = w->get_parent ();
+
+ while (w) {
+
+ if (w->is_toplevel()) {
+ /* Setting the focus widget to a Gtk::Window causes all
+ * subsequent calls to ::has_focus() on the nominal
+ * focus widget in that window to return
+ * false. Workaround: never set focus to the toplevel
+ * itself.
+ */
+ break;
+ }
+
+ if (w->get_can_focus ()) {
+ Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
+ win->set_focus (*w);
+ return;
+ }
+ w = w->get_parent ();
+ }
+
+ if (top == &_main_window) {
+
+ }
+
+ /* no focusable parent found, cancel focus in top level window.
+ C++ API cannot be used for this. Thanks, references.
+ */
+
+ gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
+
}