diff options
author | Cosimo Cecchi <cosimoc@gnome.org> | 2011-05-23 16:47:00 -0400 |
---|---|---|
committer | Cosimo Cecchi <cosimoc@gnome.org> | 2011-05-23 16:47:00 -0400 |
commit | b3a9bab703c13917af42fd53d42526c78a4702d1 (patch) | |
tree | da0151ff27c4b069130457829f298e28f6d8d11f | |
parent | a9e6a584f3948421253a980a4bb872f0d646ce04 (diff) | |
download | nautilus-b3a9bab703c13917af42fd53d42526c78a4702d1.tar.gz |
window: reverse the order of key-press event processing
Usually the default GtkWindow handler for key-press events processes
them in the following order:
- calls gtk_window_activate_key() to process mnemonics/accelerators for
the toplevel window
- calls gtk_window_propagate_key_event() to propagate the events to the
focus widget
- chains up to parent if both fail
We want gtk_window_propagate_key_event() to be called before
gtk_window_activate_key(), as when we're focusing an editable widget
(e.g. renaming a file), we want all keybindings to apply to that, e.g.
Delete, Ctrl+Delete (or Ctrl+W if we're e.g. using an emacs-mode
GTK+ binding set). This interferes a bit with the type-ahead search
windows that NautilusIconContainer and GtkTreeView pop up; we can
control the former, but not the latter, so we need a bit of a hack in
NautilusListView to prevent the search window to steal the pasted URI,
and still not handle the event.
https://bugzilla.gnome.org/show_bug.cgi?id=314431
-rw-r--r-- | libnautilus-private/nautilus-icon-container.c | 9 | ||||
-rw-r--r-- | src/nautilus-list-view.c | 32 | ||||
-rw-r--r-- | src/nautilus-window.c | 29 |
3 files changed, 59 insertions, 11 deletions
diff --git a/libnautilus-private/nautilus-icon-container.c b/libnautilus-private/nautilus-icon-container.c index 3c931a862..743720b60 100644 --- a/libnautilus-private/nautilus-icon-container.c +++ b/libnautilus-private/nautilus-icon-container.c @@ -5444,12 +5444,6 @@ key_press_event (GtkWidget *widget, "context_click_background"); } break; - case GDK_KEY_v: - /* Eat Control + v to not enable type ahead */ - if ((event->state & GDK_CONTROL_MASK) != 0) { - handled = TRUE; - } - break; default: break; } @@ -5465,7 +5459,8 @@ key_press_event (GtkWidget *widget, if (!handled && event->keyval != GDK_KEY_slash /* don't steal slash key event, used for "go to" */ && event->keyval != GDK_KEY_BackSpace && - event->keyval != GDK_KEY_Delete) { + event->keyval != GDK_KEY_Delete && + !(event->keyval == GDK_KEY_v && event->state == GDK_CONTROL_MASK)) { GdkEvent *new_event; GdkWindow *window; char *old_text; diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c index 3c243a49d..10c17151d 100644 --- a/src/nautilus-list-view.c +++ b/src/nautilus-list-view.c @@ -994,6 +994,20 @@ subdirectory_unloaded_callback (NautilusListModel *model, } static gboolean +key_release_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data) +{ + switch (event->keyval) { + case GDK_KEY_v: + /* Re-enable tree search entry; disabled in key_press_callback */ + if ((event->state & GDK_CONTROL_MASK) != 0) { + gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget), TRUE); + } + } + + return FALSE; +} + +static gboolean key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data) { NautilusView *view; @@ -1064,9 +1078,21 @@ key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_dat handled = TRUE; break; case GDK_KEY_v: - /* Eat Control + v to not enable type ahead */ + /* HACK: see https://bugzilla.gnome.org/show_bug.cgi?id=314431 + * + * We force event propagating to the focus window before the keybindings + * in nautilus-window.c:nautilus_window_key_press_event(), + * but that will trigger the type-ahead window when Ctrl+V is pressed. + * We used to special-case Ctrl+V here, and handle the event, + * to block the default GtkTreeView handler to run and show the window, + * but that's ineffective as well, because it would break Copy/Paste, as keybindings + * are now processed later, and they won't run if we return TRUE here. + * So, we resort to disabling search while the handler runs, and re-enable it later + * in the key_release callback, while not handling the event, so the accelerator + * can still run. + */ if ((event->state & GDK_CONTROL_MASK) != 0) { - handled = TRUE; + gtk_tree_view_set_enable_search (tree_view, FALSE); } break; @@ -1612,6 +1638,8 @@ create_and_set_up_tree_view (NautilusListView *view) G_CALLBACK (button_release_callback), view, 0); g_signal_connect_object (view->details->tree_view, "key_press_event", G_CALLBACK (key_press_callback), view, 0); + g_signal_connect_object (view->details->tree_view, "key_release_event", + G_CALLBACK (key_release_callback), view, 0); g_signal_connect_object (view->details->tree_view, "popup_menu", G_CALLBACK (popup_menu_callback), view, 0); g_signal_connect_object (view->details->tree_view, "row_expanded", diff --git a/src/nautilus-window.c b/src/nautilus-window.c index dc92a1df1..ab5f166f0 100644 --- a/src/nautilus-window.c +++ b/src/nautilus-window.c @@ -1104,10 +1104,27 @@ static gboolean nautilus_window_key_press_event (GtkWidget *widget, GdkEventKey *event) { + static gpointer grand_parent_class = NULL; NautilusWindow *window; int i; + gboolean handled; window = NAUTILUS_WINDOW (widget); + handled = FALSE; + + if (!grand_parent_class) { + grand_parent_class = g_type_class_peek_parent (nautilus_window_parent_class); + } + + /* See https://bugzilla.gnome.org/show_bug.cgi?id=314431 + * + * We need to handle the keybindings for the currently focused widget + * before the common accelerator bindings. + */ + handled = gtk_window_propagate_key_event (GTK_WINDOW (window), event); + if (handled) { + return TRUE; + } for (i = 0; i < G_N_ELEMENTS (extra_window_keybindings); i++) { if (extra_window_keybindings[i].keyval == event->keyval) { @@ -1125,14 +1142,22 @@ nautilus_window_key_press_event (GtkWidget *widget, g_assert (action != NULL); if (gtk_action_is_sensitive (action)) { gtk_action_activate (action); - return TRUE; + handled = TRUE; } break; } } - return GTK_WIDGET_CLASS (nautilus_window_parent_class)->key_press_event (widget, event); + if (!handled) { + handled = gtk_window_activate_key (GTK_WINDOW (window), event); + } + + if (!handled) { + handled = GTK_WIDGET_CLASS (grand_parent_class)->key_press_event (widget, event); + } + + return handled; } /* |