+void
+ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
+{
+ /* icons, titles, WM stuff */
+
+ static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
+
+ if (window_icons.empty()) {
+ Glib::RefPtr<Gdk::Pixbuf> icon;
+ if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
+ window_icons.push_back (icon);
+ }
+ if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
+ window_icons.push_back (icon);
+ }
+ if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
+ window_icons.push_back (icon);
+ }
+ if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
+ window_icons.push_back (icon);
+ }
+ }
+
+ if (!window_icons.empty()) {
+ window.set_default_icon_list (window_icons);
+ }
+
+ Gtkmm2ext::WindowTitle title (Glib::get_application_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);
+ window.signal_key_release_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* event_window)
+{
+ Gtkmm2ext::Bindings* bindings = 0;
+ Gtk::Window* window = 0;
+
+ /* 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 */
+
+ if (w) {
+ bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
+ }
+
+ DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
+
+ } else {
+
+ 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);
+}
+
+static Gtkmm2ext::Bindings*
+get_bindings_from_widget_heirarchy (GtkWidget* w)
+{
+ void* p;
+
+ while (w) {
+ if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
+ break;
+ }
+ w = gtk_widget_get_parent (w);
+ }
+
+ return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
+}
+
+bool
+ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
+{
+ GtkWindow* win = window.gobj();
+ GtkWidget* focus = gtk_window_get_focus (win);
+ bool special_handling_of_unmodified_accelerators = false;
+ const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
+
+ 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;
+
+ } else {
+
+ Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
+ 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 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),
+ special_handling_of_unmodified_accelerators,
+ Keyboard::some_magic_widget_has_focus(),
+ focus,
+ (focus ? gtk_widget_get_name (focus) : "no focus widget"),
+ ((ev->state & mask) ? "yes" : "no")));
+
+ /* 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.
+ */
+
+
+ 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, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
+
+ 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 && 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 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 && 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 ()
+{
+ if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
+ error << _("Global keybindings are missing") << endmsg;
+ }
+}
+