summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCosimo Cecchi <cosimoc@gnome.org>2011-05-23 16:47:00 -0400
committerCosimo Cecchi <cosimoc@gnome.org>2011-05-23 16:47:00 -0400
commitb3a9bab703c13917af42fd53d42526c78a4702d1 (patch)
treeda0151ff27c4b069130457829f298e28f6d8d11f
parenta9e6a584f3948421253a980a4bb872f0d646ce04 (diff)
downloadnautilus-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.c9
-rw-r--r--src/nautilus-list-view.c32
-rw-r--r--src/nautilus-window.c29
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;
}
/*