[nautilus] window: reverse the order of key-press event processing



commit f76c50a0e46aa7786820f76b3f71b57b44b8d7fb
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Mon May 23 16:47:00 2011 -0400

    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

 libnautilus-private/nautilus-icon-container.c |    9 +-----
 src/nautilus-list-view.c                      |   32 +++++++++++++++++++++++-
 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 2152373..9c33549 100644
--- a/libnautilus-private/nautilus-icon-container.c
+++ b/libnautilus-private/nautilus-icon-container.c
@@ -5510,12 +5510,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;
 		}
@@ -5531,7 +5525,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 e8632f3..f1530b9 100644
--- a/src/nautilus-list-view.c
+++ b/src/nautilus-list-view.c
@@ -1006,6 +1006,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;
@@ -1076,9 +1090,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;
 
@@ -1624,6 +1650,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 dc92a1d..ab5f166 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;
 }
 
 /*



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]