#include "audio_clock.h"
#include "audio_region_view.h"
#include "big_clock_window.h"
-#include "binding_owners.h"
#include "bundle_manager.h"
#include "duplicate_routes_dialog.h"
+#include "debug.h"
#include "engine_dialog.h"
#include "export_video_dialog.h"
#include "export_video_infobox.h"
, meterbridge (0)
, rc_option_editor (0)
, speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
- , key_editor (X_("key-editor"), _("Key Bindings"))
, add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
, about (X_("about"), _("About"))
, location_ui (X_("locations"), _("Locations"))
, audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
, export_video_dialog (X_("video-export"), _("Video Export Dialog"))
, session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
- , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
+ , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
, bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
, big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
, audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
, midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
+ , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
, video_server_process (0)
, splash (0)
, have_configure_timeout (false)
audio_port_matrix.set_state (*ui_xml, 0);
midi_port_matrix.set_state (*ui_xml, 0);
export_video_dialog.set_state (*ui_xml, 0);
-
- /* tabbables */
- // rc_option_editor->set_state (*ui_xml, 0);
- // editor->set_state (*ui_xml, 0);
- // mixer->set_state (*ui_xml, 0);
}
+ /* Separate windows */
+
WM::Manager::instance().register_window (&key_editor);
- // WM::Manager::instance().register_window (&rc_option_editor);
WM::Manager::instance().register_window (&session_option_editor);
WM::Manager::instance().register_window (&speaker_config_window);
WM::Manager::instance().register_window (&about);
}
void
-ARDOUR_UI::update_autosave ()
+ARDOUR_UI::session_dirty_changed ()
{
- ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
+ update_autosave ();
+ update_title ();
+}
+void
+ARDOUR_UI::update_autosave ()
+{
if (_session && _session->dirty()) {
if (_autosave_connection.connected()) {
_autosave_connection.disconnect();
#endif
}
+static bool
+_hide_splash (gpointer arg)
+{
+ ((ARDOUR_UI*)arg)->hide_splash();
+ return false;
+}
+
int
ARDOUR_UI::starting ()
{
use_config ();
- goto_editor_window ();
-
WM::Manager::instance().show_visible ();
/* We have to do this here since goto_editor_window() ends up calling show_all() on the
_status_bar_visibility.update ();
BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
+
+ if (splash && splash->is_visible()) {
+ // in 1 second, hide the splash screen
+ Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
+ }
+
+ /* all other dialogs are created conditionally */
+
return 0;
}
if (get_session_parameters (true, false)) {
exit (1);
}
-
- goto_editor_window ();
}
/** @param snap_name Snapshot name (without .ardour suffix).
session_loaded = true;
- goto_editor_window ();
-
if (_session) {
_session->set_clean ();
}
return node;
}
+XMLNode*
+ARDOUR_UI::main_window_settings () const
+{
+ XMLNode* node = 0;
+
+ if (_session) {
+ node = _session->instant_xml(X_("Main"));
+ } else {
+ node = Config->instant_xml(X_("Main"));
+ }
+
+ if (!node) {
+ if (getenv("ARDOUR_INSTANT_XML_PATH")) {
+ node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
+ }
+ }
+
+ if (!node) {
+ node = new XMLNode (X_("Main"));
+ }
+
+ return node;
+}
+
XMLNode*
ARDOUR_UI::editor_settings () const
{
}
Gtkmm2ext::WindowTitle title (Glib::get_application_name());
- title += name;
+
+ if (!name.empty()) {
+ title += name;
+ }
+
window.set_title (title.get_string());
window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
window.set_flags (CAN_FOCUS);
window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
+ /* This is a hack to ensure that GTK-accelerators continue to
+ * work. Once we switch over to entirely native bindings, this will be
+ * unnecessary and should be removed
+ */
+ window.add_accel_group (ActionManager::ui_manager->get_accel_group());
+
window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
}
bool
-ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* window)
+ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
{
- switch (ev->type) {
- case GDK_KEY_PRESS:
- return key_press_handler (ev, window);
- default:
- break;
- }
+ Gtkmm2ext::Bindings* bindings = 0;
+ Gtk::Window* window = 0;
- return key_release_handler (ev, window);
-}
-
-bool
-ARDOUR_UI::key_press_handler (GdkEventKey* ev, Gtk::Window* event_window)
-{
+ /* until we get ardour bindings working, we are not handling key
+ * releases yet.
+ */
+
+ if (ev->type != GDK_KEY_PRESS) {
+ return false;
+ }
+
if (event_window == &_main_window) {
+
+ window = event_window;
+
/* find current tab contents */
Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
/* see if it uses the ardour binding system */
- HasBindings* bindable;
-
- if ((bindable = dynamic_cast<HasBindings*> (w)) != 0) {
- KeyboardKey k (ev->state, ev->keyval);
- return bindable->bindings().activate (k, Bindings::Press);
+ if (w) {
+ bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
} else {
- /* no bindings in current tab, use baroque GTK mechanism */
- return key_press_focus_accelerator_handler (_main_window, ev);
+ bindings = &global_bindings;
}
- } else {
- /* no window supplied, try our own bindings */
- KeyboardKey k (ev->state, ev->keyval);
- return _global_bindings.activate (k, Bindings::Press);
+ DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
+
+ } else if (event_window != 0) {
+
+ window = event_window;
+
+ /* see if window uses ardour binding system */
+
+ bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
+
+ }
+
+ /* An empty binding set is treated as if it doesn't exist */
+
+ if (bindings && bindings->empty()) {
+ bindings = 0;
}
+
+ return key_press_focus_accelerator_handler (*window, ev, bindings);
}
-
+
bool
-ARDOUR_UI::key_release_handler (GdkEventKey* ev, Gtk::Window* event_window)
+ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
{
- if (event_window == &_main_window) {
- /* find current tab contents */
+ GtkWindow* win = window.gobj();
+ GtkWidget* focus = gtk_window_get_focus (win);
+ bool special_handling_of_unmodified_accelerators = false;
+ /* consider all relevant modifiers but not LOCK or SHIFT */
+ const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
- Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
+ GdkModifierType modifier = GdkModifierType (ev->state);
+ modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
+ Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
- /* see if it uses the ardour binding system */
+ if (focus) {
+
+ /* some widget has keyboard focus */
+
+ if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
+
+ /* A particular kind of focusable widget currently has keyboard
+ * focus. All unmodified key events should go to that widget
+ * first and not be used as an accelerator by default
+ */
+
+ special_handling_of_unmodified_accelerators = true;
+ }
+ }
+
+ DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7\n",
+ win,
+ ev->keyval,
+ show_gdk_event_state (ev->state),
+ special_handling_of_unmodified_accelerators,
+ Keyboard::some_magic_widget_has_focus(),
+ focus,
+ (focus ? gtk_widget_get_name (focus) : "no focus widget")));
+
+ /* This exists to allow us to override the way GTK handles
+ key events. The normal sequence is:
+
+ a) event is delivered to a GtkWindow
+ b) accelerators/mnemonics are activated
+ c) if (b) didn't handle the event, propagate to
+ the focus widget and/or focus chain
+
+ The problem with this is that if the accelerators include
+ keys without modifiers, such as the space bar or the
+ letter "e", then pressing the key while typing into
+ a text entry widget results in the accelerator being
+ activated, instead of the desired letter appearing
+ in the text entry.
+
+ There is no good way of fixing this, but this
+ represents a compromise. The idea is that
+ key events involving modifiers (not Shift)
+ get routed into the activation pathway first, then
+ get propagated to the focus widget if necessary.
+
+ If the key event doesn't involve modifiers,
+ we deliver to the focus widget first, thus allowing
+ it to get "normal text" without interference
+ from acceleration.
+
+ Of course, this can also be problematic: if there
+ is a widget with focus, then it will swallow
+ all "normal text" accelerators.
+ */
- HasBindings* bindable;
- if ((bindable = dynamic_cast<HasBindings*> (w)) != 0) {
- KeyboardKey k (ev->state, ev->keyval);
- return bindable->bindings().activate (k, Bindings::Release);
- } else {
- /* no bindings in current tab, use baroque GTK mechanism */
- return key_press_focus_accelerator_handler (_main_window, ev);
+ if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
+
+ /* no special handling or there are modifiers in effect: accelerate first */
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
+ DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
+ ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
+ KeyboardKey k (ev->state, ev->keyval);
+
+ if (bindings) {
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
+
+ if (bindings->activate (k, Bindings::Press)) {
+ DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+ return true;
+ }
+ }
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
+
+ if (global_bindings.activate (k, Bindings::Press)) {
+ DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+ return true;
}
+ DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
+
+ if (gtk_window_propagate_key_event (win, ev)) {
+ DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
+ return true;
+ }
+
} else {
- /* no window supplied, try our own bindings */
- KeyboardKey k (ev->state, ev->keyval);
- return _global_bindings.activate (k, Bindings::Release);
->>>>>>> first compilable version of tabbable design.
+
+ /* no modifiers, propagate first */
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
+
+ if (gtk_window_propagate_key_event (win, ev)) {
+ DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
+ return true;
+ }
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
+ KeyboardKey k (ev->state, ev->keyval);
+
+ if (bindings) {
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
+
+
+ if (bindings->activate (k, Bindings::Press)) {
+ DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+ return true;
+ }
+
+ }
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
+
+ if (global_bindings.activate (k, Bindings::Press)) {
+ DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+ return true;
+ }
}
+
+ DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
+ return true;
}
+
+void
+ARDOUR_UI::load_bindings ()
+{
+ global_bindings.set_action_map (global_actions);
+ global_bindings.load (X_("global"));
+}
+