GNOME Bugzilla – Bug 362273
menu accel keys override entry box input
Last modified: 2014-08-30 05:04:59 UTC
Either change the default behavior so that an active entry box does not lose keystrokes to a menu accelerator in the same window or improve the documentation to describe to a newbie how to fix it (eg. in the menu box documentation). Other information: // Here's an example program that shows my problem // I can't enter an 'n' into the entry box. #include <stdio.h> #include <gtk/gtk.h> void myAction(GtkAction *action, gpointer user_data) { printf("Hi\n"); } int main(int argc, char *argv[]) { gtk_init(&argc, &argv); GtkWidget *window; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget *vbox; vbox = gtk_vbox_new(FALSE, 0); gtk_container_add (GTK_CONTAINER(window), vbox); static GtkActionEntry entries[] = { { "FileMenu", NULL, "_File" }, { "New", GTK_STOCK_NEW, "_New", "n", NULL, G_CALLBACK (myAction) }, }; static const gchar *ui_info = "<ui>\n" " <menubar name='MenuBar'>\n" " <menu action='FileMenu'>\n" " <menuitem action='New'/>\n" " </menu>\n" " </menubar>\n" "</ui>"; GtkUIManager *manager; GtkActionGroup *actions; actions = gtk_action_group_new ("Actions"); gtk_action_group_add_actions (actions, entries, G_N_ELEMENTS (entries), NULL); manager = gtk_ui_manager_new (); GError *err; err = NULL; gtk_ui_manager_add_ui_from_string (manager, ui_info, -1, &err); gtk_ui_manager_insert_action_group (manager, actions, 0); gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (manager)); GtkWidget *mw = gtk_ui_manager_get_widget (manager, "/MenuBar"); gtk_box_pack_start (GTK_BOX (vbox), mw, FALSE, FALSE, 0); GtkWidget *entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0); gtk_widget_show_all(window); gtk_main(); }
I think the "n" there should be "<control>n" , no?
No, in this example, the "n" was intended to make the accelerator key an "n", not a "<control-n>. I guess the fact that I used this to mean "New" in this example might have been misleading, but I do want an accelerator that is a regular single key. I'm trying to port a program written in tcl/tk that has single key accelarators to gtk+. Down at the bottom of one window that has single key menu accelerators, I want a little entry box into which I can type a string to search for in a scrolling text box above and I want to be able to search for arbitrary text, not just text that doesn't conflict with the menu accelerator.
gtk does not work like that. menu accelerators take precedence over regular input. So, if you use menu accelerators without modifiers, these keys are no longer available for input.
(In reply to comment #3) > gtk does not work like that. Not until this usability request is addressed you mean. ;) If this is a "will not fix" type of request, then I think the accelerator documentation should explicity state that it will override all other widgets in that window. Should I file a new documentation request?
Changing this is certain certain to cause all kinds of problems existing applications, so yes, this is a wontfix. If you really think you need this kind of behaviour, you can install a key snooper and bypass the normal gtk event handling if your entry has focus. Feel free to move this bug to the docs .
(In reply to comment #5) > Changing this is certain certain to cause all kinds of problems > existing applications, so yes, this is a wontfix. Just to play devil's advocate for a minute, I can't believe there are many applications that have unmodified accelerators and entry boxes in the same window or they would have had the same problem that I'm having. I can't imagine a scenario where somebody would want keystrokes to an active entry box that would otherwise display as text in the entry box stolen by the accelerator. Can you point me to such an application? Even if there are such applications, perhaps a solution would be to not change the default behavior, but to add a non-default mechanism to steal back printing characters from the menu accelerator to an active entry box (eg: a way to tell the menu accelerator to handle printing characters after other widgets in the window get a crack at them instead of before... like gtk_ui_manager_handle_printing_characters_last(manager)). (I'm not trying to be difficult... just making suggestions)
paul@linuxaudiosystems.com provide this workaround code on the gtk mailing list. Perhaps something similar could be incorporated into gtk as a non-default mode? bool key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) { GtkWindow* win = window.gobj(); GtkWidget* focus = gtk_window_get_focus (win); bool special_handling_of_unmodified_accelerators = false; if (focus) { if (GTK_IS_ENTRY(focus)) { special_handling_of_unmodified_accelerators = true; } } /* 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) { /* pretend that certain key events that GTK does not allow to be used as accelerators are actually something that it does allow. */ int ret = false; switch (ev->keyval) { case GDK_Up: ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_uparrow, GdkModifierType(ev->state)); break; case GDK_Down: ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_downarrow, GdkModifierType(ev->state)); break; case GDK_Right: ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_rightarrow, GdkModifierType(ev->state)); break; case GDK_Left: ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_leftarrow, GdkModifierType(ev->state)); break; default: break; } if (ret) { return true; } } if (!special_handling_of_unmodified_accelerators || ev->state & (Gdk::MOD1_MASK| Gdk::MOD3_MASK| Gdk::MOD4_MASK| Gdk::MOD5_MASK| Gdk::CONTROL_MASK)) { /* no special handling or modifiers in effect: accelerate first */ if (!gtk_window_activate_key (win, ev)) { return gtk_window_propagate_key_event (win, ev); } else { return true; } } /* no modifiers, propagate first */ if (!gtk_window_propagate_key_event (win, ev)) { return gtk_window_activate_key (win, ev); } return true; }
A perfect example of this, which I just ran into with gnome-3 (bug 651344), is where I changed the new Control+Delete accelerator for "Move to wastebasket" back to just Delete. I then found that the delete key accelerator was taking precedence when renaming a file, causing the file to be deleted, rather than the text from the filename. Previous versions of nautilus had this key as the default, so is this a nautilus bug, or a gtk+ usability bug?
GtkAction has been deprecated