diff options
Diffstat (limited to 'nautilus-restore-typeahead.patch')
-rw-r--r-- | nautilus-restore-typeahead.patch | 1403 |
1 files changed, 298 insertions, 1105 deletions
diff --git a/nautilus-restore-typeahead.patch b/nautilus-restore-typeahead.patch index 8d2b2bf521ce..aa37e71598d8 100644 --- a/nautilus-restore-typeahead.patch +++ b/nautilus-restore-typeahead.patch @@ -1,1136 +1,329 @@ diff --git a/data/org.gnome.nautilus.gschema.xml b/data/org.gnome.nautilus.gschema.xml -index 4b393f83f..2c96e9c0c 100644 +index 94b17208d..438008f15 100644 --- a/data/org.gnome.nautilus.gschema.xml +++ b/data/org.gnome.nautilus.gschema.xml -@@ -192,6 +192,11 @@ - <summary>What viewer should be used when searching</summary> - <description>When searching Nautilus will switch to the type of view in this setting.</description> +@@ -77,6 +77,11 @@ + <summary>Always use the location entry, instead of the pathbar</summary> + <description>If set to true, then Nautilus browser windows will always use a textual input entry for the location toolbar, instead of the pathbar.</description> </key> -+ <key name="enable-interactive-search" type="b"> ++ <key type="b" name="type-ahead-search"> + <default>true</default> -+ <summary>Enable interactive (type-ahead) search</summary> -+ <description>If set to true, enables interactive search, similar to Nautilus 3.4.</description> ++ <summary>Start searching on type ahead</summary> ++ <description>If set to true, typing on the files viewer will start searching. Otherwise it select first matching file.</description> + </key> - <key type="b" name="open-folder-on-dnd-hover"> - <default>true</default> - <summary>Whether to open the hovered folder after a timeout when drag and drop operation</summary> + <key name="recursive-search" enum="org.gnome.nautilus.SpeedTradeoff"> + <default>'local-only'</default> + <summary>Where to perform recursive search</summary> diff --git a/src/nautilus-global-preferences.h b/src/nautilus-global-preferences.h -index 87a79e706..109c2e6e2 100644 +index 9d39bbc03..27c2e54f1 100644 --- a/src/nautilus-global-preferences.h +++ b/src/nautilus-global-preferences.h -@@ -140,6 +140,9 @@ typedef enum - /* Recent files */ - #define NAUTILUS_PREFERENCES_RECENT_FILES_ENABLED "remember-recent-files" - -+/* Interactive search (typeahead) */ -+#define NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH "enable-interactive-search" -+ - /* Default view when searching */ - #define NAUTILUS_PREFERENCES_SEARCH_VIEW "search-view" - -diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c -index 6b78eded4..594d8fcde 100644 ---- a/src/nautilus-list-view.c -+++ b/src/nautilus-list-view.c -@@ -3080,6 +3080,7 @@ nautilus_list_view_set_selection (NautilusFilesView *view, - gboolean cursor_is_set_on_selection = FALSE; - GList *iters, *l; - NautilusFile *file; -+ GtkTreePath *path2 = NULL; - - list_view = NAUTILUS_LIST_VIEW (view); - model = list_view->details->model; -@@ -3111,10 +3112,22 @@ nautilus_list_view_set_selection (NautilusFilesView *view, - - gtk_tree_selection_select_iter (tree_selection, - (GtkTreeIter *) l->data); -+ if (!path2) -+ path2 = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), (GtkTreeIter *) l->data); - } -+ - g_list_free_full (iters, g_free); - } - -+ if (path2) { -+ gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view, -+ path2, -+ list_view->details->file_name_column, -+ GTK_CELL_RENDERER (list_view->details->file_name_cell), -+ TRUE); -+ gtk_tree_path_free (path2); +@@ -116,6 +116,7 @@ typedef enum + + /* Search behaviour */ + #define NAUTILUS_PREFERENCES_RECURSIVE_SEARCH "recursive-search" ++#define NAUTILUS_PREFERENCES_TYPE_AHEAD_SEARCH "type-ahead-search" + + /* Context menu options */ + #define NAUTILUS_PREFERENCES_SHOW_DELETE_PERMANENTLY "show-delete-permanently" +diff --git a/src/nautilus-preferences-window.c b/src/nautilus-preferences-window.c +index a1cd95823..b5e167120 100644 +--- a/src/nautilus-preferences-window.c ++++ b/src/nautilus-preferences-window.c +@@ -41,6 +41,8 @@ + "show_create_link_switch" + #define NAUTILUS_PREFERENCES_DIALOG_LIST_VIEW_USE_TREE_WIDGET \ + "use_tree_view_switch" ++#define NAUTILUS_PREFERENCES_DIALOG_TYPE_AHEAD_WIDGET \ ++ "type_ahead_search" + + /* combo preferences */ + #define NAUTILUS_PREFERENCES_DIALOG_OPEN_ACTION_COMBO \ +@@ -334,6 +336,9 @@ nautilus_preferences_window_setup (GtkBuilder *builder) + bind_builder_bool (builder, nautilus_preferences, + NAUTILUS_PREFERENCES_DIALOG_DELETE_PERMANENTLY_WIDGET, + NAUTILUS_PREFERENCES_SHOW_DELETE_PERMANENTLY); ++ bind_builder_bool (builder, nautilus_preferences, ++ NAUTILUS_PREFERENCES_DIALOG_TYPE_AHEAD_WIDGET, ++ NAUTILUS_PREFERENCES_TYPE_AHEAD_SEARCH); + + bind_builder_combo_row (builder, nautilus_preferences, + NAUTILUS_PREFERENCES_DIALOG_OPEN_ACTION_COMBO, +diff --git a/src/nautilus-query-editor.c b/src/nautilus-query-editor.c +index 95b284b7d..4ca27b001 100644 +--- a/src/nautilus-query-editor.c ++++ b/src/nautilus-query-editor.c +@@ -742,6 +742,12 @@ nautilus_query_editor_set_query (NautilusQueryEditor *self, + + g_return_if_fail (NAUTILUS_IS_QUERY_EDITOR (self)); + ++ /* Setting query to NULL causes reentry to set it to an empty query */ ++ if (self->change_frozen) { ++ g_set_object (&self->query, query); ++ return; + } + - g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view); - nautilus_files_view_notify_selection_changed (view); - } -@@ -4077,3 +4090,9 @@ nautilus_list_view_new (NautilusWindowSlot *slot) - "window-slot", slot, - NULL); - } -+ -+GtkTreeView * -+nautilus_list_view_get_tree_view (NautilusListView *list_view) -+{ -+ return list_view->details->tree_view; -+} -diff --git a/src/nautilus-list-view.h b/src/nautilus-list-view.h -index 7e19621e8..b568b9f71 100644 -@@ -37,4 +37,5 @@ struct _NautilusListView - NautilusListViewDetails *details; - }; - --NautilusFilesView * nautilus_list_view_new (NautilusWindowSlot *slot); -\ No newline at end of file -+NautilusFilesView * nautilus_list_view_new (NautilusWindowSlot *slot); -+GtkTreeView * nautilus_list_view_get_tree_view (NautilusListView *list_view); + if (query != NULL) + { + text = nautilus_query_get_text (query); diff --git a/src/nautilus-window-slot.c b/src/nautilus-window-slot.c -index b3a7bc211..0e126a563 100644 +index ac367db12..567df1c88 100644 --- a/src/nautilus-window-slot.c +++ b/src/nautilus-window-slot.c -@@ -23,6 +23,9 @@ - - #include "nautilus-window-slot.h" - -+#include "nautilus-canvas-view.h" -+#include "nautilus-list-view.h" -+ - #include "nautilus-application.h" - #include "nautilus-bookmark.h" - #include "nautilus-bookmark-list.h" -@@ -126,6 +129,17 @@ typedef struct - gboolean tried_mount; - gint view_mode_before_search; - -+ /* Interactive search */ -+ gboolean isearch_enable; -+ gboolean isearch_imcontext_changed; -+ gboolean isearch_disable_hide; -+ NautilusFile *isearch_selected_file; -+ GtkWidget *isearch_window; -+ GtkWidget *isearch_entry; -+ gulong isearch_entry_changed_id; -+ guint isearch_timeout_id; -+ gulong isearch_configure_event_id; -+ - /* Menus */ - GMenu *extensions_background_menu; - GMenu *templates_menu; -@@ -227,6 +241,98 @@ nautilus_window_slot_get_restore_tab_data (NautilusWindowSlot *self) - return data; - } - -+ -+/* Interactive search */ -+static void isearch_ensure (NautilusWindowSlot *slot); -+ -+static gboolean isearch_start (NautilusWindowSlot *slot, -+ GdkDevice *device); -+ -+static void isearch_enable_changed (gpointer callback_data); -+ -+static void isearch_dispose (NautilusWindowSlot *slot); -+ -+static void isearch_hide (NautilusWindowSlot *slot, -+ GdkDevice *device); -+ -+static gboolean isearch_timeout (gpointer user_data); -+ -+static void isearch_timeout_destroy (gpointer user_data); -+ -+static void isearch_timeout_restart (NautilusWindowSlot *slot); -+ -+static gboolean isearch_window_delete_event (GtkWidget *widget, -+ GdkEventAny *event, -+ NautilusWindowSlot *slot); -+ -+static gboolean isearch_window_button_press_event (GtkWidget *widget, -+ GdkEventButton *event, -+ NautilusWindowSlot *slot); -+ -+static gboolean isearch_window_scroll_event (GtkWidget *widget, -+ GdkEventScroll *event, -+ NautilusWindowSlot *slot); -+ -+static void isearch_activate_items_alternate (NautilusWindowSlot *slot); -+ -+static gboolean isearch_window_key_press_event (GtkWidget *widget, -+ GdkEventKey *event, -+ NautilusWindowSlot *slot); -+ -+static void isearch_disable_hide (GtkEntry *entry, -+ GtkMenu *menu, -+ gpointer data); -+ -+static void isearch_preedit_changed (GtkEntry *entry, -+ gchar *preedit, -+ NautilusWindowSlot *slot); -+ -+static void isearch_activate_event (GtkEntry *entry, -+ NautilusWindowSlot *slot); -+ -+static gboolean isearch_enable_hide_real (gpointer data); -+ -+static void isearch_enable_hide (GtkWidget *widget, -+ gpointer data); -+ -+static void send_focus_change (GtkWidget *widget, -+ GdkDevice *device, -+ gboolean in); -+ -+static void isearch_entry_changed (GtkWidget *entry, -+ NautilusWindowSlot *slot); -+ -+static void isearch_position (NautilusWindowSlot *slot); -+ -+static gboolean isearch_compare_filename (const gchar *f1, -+ const gchar *f2, -+ guint length); -+ -+static int compare_files (gconstpointer a, -+ gconstpointer b, -+ gpointer callback_data); -+ -+static GList *isearch_get_sorted_files (NautilusWindowSlot *slot); -+ -+static NautilusFile *isearch_find (NautilusWindowSlot *slot, -+ const gchar *text); -+ -+static NautilusFile *isearch_find_next (NautilusWindowSlot *slot, -+ const gchar *text); -+ -+static NautilusFile *isearch_find_prev (NautilusWindowSlot *slot, -+ const gchar *text); -+ -+static gboolean isearch_move_next (NautilusWindowSlot *slot); -+ -+static gboolean isearch_move_prev (NautilusWindowSlot *slot); -+ -+static void isearch_set_selection (NautilusWindowSlot *slot, -+ NautilusFile *file); -+ -+#define ISEARCH_TIMEOUT 5000 -+ -+ - gboolean - nautilus_window_slot_handles_location (NautilusWindowSlot *self, - GFile *location) -@@ -658,15 +764,70 @@ nautilus_window_slot_handle_event (NautilusWindowSlot *self, - } - } - -- /* If the action is not enabled, don't try to handle search */ -- if (g_action_get_enabled (action)) -- { -- retval = nautilus_query_editor_handle_event (priv->query_editor, event); -- } -+ if (priv->isearch_enable) { -+ GdkEvent *new_event; -+ gchar *old_text; -+ const gchar *new_text; -+ GdkScreen *screen; -+ gboolean text_modified; -+ gulong popup_menu_id; -+ -+ isearch_ensure (self); -+ -+ /* Make a copy of the current text */ -+ old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry))); -+ new_event = gdk_event_copy ((GdkEvent *) event); -+ g_object_unref (((GdkEventKey *) new_event)->window); -+ -+ ((GdkEventKey *) new_event)->window = -+ g_object_ref (gtk_widget_get_window (priv->isearch_window)); -+ gtk_widget_realize (priv->isearch_window); -+ -+ popup_menu_id = g_signal_connect (priv->isearch_entry, -+ "popup-menu", G_CALLBACK (gtk_true), -+ NULL); -+ -+ /* Move the entry off screen */ -+ screen = gtk_widget_get_screen (GTK_WIDGET (self)); -+ gtk_window_move (GTK_WINDOW (priv->isearch_window), -+ gdk_screen_get_width (screen) + 1, -+ gdk_screen_get_height (screen) + 1); -+ gtk_widget_show (priv->isearch_window); -+ -+ /* Send the event to the window. If the preedit_changed signal is emitted during this -+ * event, we will set priv->imcontext_changed */ -+ priv->isearch_imcontext_changed = FALSE; -+ retval = gtk_widget_event (priv->isearch_window, new_event); -+ gdk_event_free (new_event); -+ gtk_widget_hide (priv->isearch_window); -+ -+ g_signal_handler_disconnect (priv->isearch_entry, popup_menu_id); -+ -+ /* We check to make sure that the entry tried to handle the text, and that the text has -+ * changed. */ -+ new_text = gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry)); -+ text_modified = strcmp (old_text, new_text) != 0; -+ g_free (old_text); -+ -+ if (priv->isearch_imcontext_changed || (retval && text_modified)) { -+ if (isearch_start (self, gdk_event_get_device ((GdkEvent *) event))) { -+ gtk_widget_grab_focus (GTK_WIDGET (self)); -+ return TRUE; -+ } -+ gtk_entry_set_text (GTK_ENTRY (priv->isearch_entry), ""); -+ return FALSE; -+ } -+ } else { -+ /* If the action is not enabled, don't try to handle search */ -+ if (g_action_get_enabled (action)) -+ { -+ retval = nautilus_query_editor_handle_event (priv->query_editor, event); -+ } - -- if (retval) -- { -- nautilus_window_slot_set_search_visible (self, TRUE); -+ if (retval) -+ { -+ nautilus_window_slot_set_search_visible (self, TRUE); -+ } +@@ -67,6 +67,9 @@ enum + + #define FILE_SHARING_SCHEMA_ID "org.gnome.desktop.file-sharing" + ++/* In type ahead mode, clear entry if it did not change for a while */ ++#define CLEAR_QUERY_EDITOR_TIMEOUT 1000 ++ + struct _NautilusWindowSlot + { + GtkBox parent_instance; +@@ -105,10 +108,7 @@ struct _NautilusWindowSlot + /* Query editor */ + NautilusQueryEditor *query_editor; + NautilusQuery *pending_search_query; +- gulong qe_changed_id; +- gulong qe_cancel_id; +- gulong qe_activated_id; +- gulong qe_focus_view_id; ++ guint clear_query_editor_timeout_id; + + GtkLabel *search_info_label; + GtkRevealer *search_info_label_revealer; +@@ -176,6 +176,7 @@ static void real_set_templates_menu (NautilusWindowSlot *self, + GMenuModel *menu); + static GMenuModel *real_get_templates_menu (NautilusWindowSlot *self); + static void nautilus_window_slot_setup_extra_location_widgets (NautilusWindowSlot *self); ++static GFile *nautilus_window_slot_get_current_location (NautilusWindowSlot *self); + + void + free_navigation_state (gpointer data) +@@ -426,6 +427,37 @@ query_editor_focus_view_callback (NautilusQueryEditor *editor, } - - return retval; -@@ -1206,6 +1367,14 @@ nautilus_window_slot_init (NautilusWindowSlot *self) - nautilus_application_set_accelerator (app, "slot.files-view-mode(uint32 0)", "<control>2"); - nautilus_application_set_accelerator (app, "slot.search-visible", "<control>f"); - -+ priv->isearch_enable = g_settings_get_boolean (nautilus_preferences, -+ NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH); -+ -+ g_signal_connect_swapped (nautilus_preferences, -+ "changed::" NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH, -+ G_CALLBACK (isearch_enable_changed), -+ self); -+ - priv->view_mode_before_search = NAUTILUS_VIEW_INVALID_ID; } - -@@ -3042,6 +3211,7 @@ nautilus_window_slot_dispose (GObject *object) - - self = NAUTILUS_WINDOW_SLOT (object); - priv = nautilus_window_slot_get_instance_private (self); -+ isearch_dispose (self); - - g_signal_handlers_disconnect_by_data (nautilus_trash_monitor_get (), self); - -@@ -3102,6 +3272,10 @@ nautilus_window_slot_finalize (GObject *object) - self = NAUTILUS_WINDOW_SLOT (object); - priv = nautilus_window_slot_get_instance_private (self); - -+ g_signal_handlers_disconnect_by_func (nautilus_preferences, -+ isearch_enable_changed, -+ self); -+ - g_clear_pointer (&priv->title, g_free); - - G_OBJECT_CLASS (nautilus_window_slot_parent_class)->finalize (object); -@@ -3566,6 +3740,13 @@ nautilus_window_slot_set_active (NautilusWindowSlot *self, - window = nautilus_window_slot_get_window (self); - g_assert (self == nautilus_window_get_active_slot (window)); - -+ isearch_hide (self, NULL); -+ if (priv->isearch_configure_event_id != 0) { -+ g_signal_handler_disconnect (GTK_WIDGET (priv->window), -+ priv->isearch_configure_event_id); -+ priv->isearch_configure_event_id = 0; -+ } -+ - gtk_widget_insert_action_group (GTK_WIDGET (window), "slot", NULL); - } - -@@ -3610,3 +3791,792 @@ nautilus_window_slot_get_query_editor (NautilusWindowSlot *self) - - return priv->query_editor; - } -+ -+/* Interactive search */ -+static void -+isearch_ensure (NautilusWindowSlot *slot) -+{ -+ GtkWidget *frame; -+ GtkWidget *vbox; -+ GtkWidget *toplevel; -+ GdkScreen *screen; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (slot)); -+ screen = gtk_widget_get_screen (GTK_WIDGET (slot)); -+ -+ if (priv->isearch_window != NULL) -+ { -+ if (gtk_window_has_group (GTK_WINDOW (toplevel))) -+ gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)), -+ GTK_WINDOW (priv->isearch_window)); -+ else if (gtk_window_has_group (GTK_WINDOW (priv->isearch_window))) -+ gtk_window_group_remove_window (gtk_window_get_group ( -+ GTK_WINDOW (priv->isearch_window)), -+ GTK_WINDOW (priv->isearch_window)); -+ -+ gtk_window_set_screen (GTK_WINDOW (priv->isearch_window), screen); -+ return; -+ } -+ -+ priv->isearch_window = gtk_window_new (GTK_WINDOW_POPUP); -+ gtk_window_set_screen (GTK_WINDOW (priv->isearch_window), screen); -+ -+ if (gtk_window_has_group (GTK_WINDOW (toplevel))) -+ gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)), -+ GTK_WINDOW (priv->isearch_window)); -+ -+ gtk_window_set_type_hint (GTK_WINDOW (priv->isearch_window), -+ GDK_WINDOW_TYPE_HINT_UTILITY); -+ gtk_window_set_modal (GTK_WINDOW (priv->isearch_window), TRUE); -+ g_signal_connect (priv->isearch_window, "delete-event", -+ G_CALLBACK (isearch_window_delete_event), slot); -+ g_signal_connect (priv->isearch_window, "key-press-event", -+ G_CALLBACK (isearch_window_key_press_event), slot); -+ g_signal_connect (priv->isearch_window, "button-press-event", -+ G_CALLBACK (isearch_window_button_press_event), slot); -+ g_signal_connect (priv->isearch_window, "scroll-event", -+ G_CALLBACK (isearch_window_scroll_event), slot); -+ -+ frame = gtk_frame_new (NULL); -+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); -+ gtk_widget_show (frame); -+ gtk_container_add (GTK_CONTAINER (priv->isearch_window), frame); -+ -+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); -+ gtk_widget_show (vbox); -+ gtk_container_add (GTK_CONTAINER (frame), vbox); -+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); -+ -+ /* add entry */ -+ priv->isearch_entry = gtk_entry_new (); -+ gtk_widget_show (priv->isearch_entry); -+ g_signal_connect (priv->isearch_entry, "populate-popup", -+ G_CALLBACK (isearch_disable_hide), slot); -+ g_signal_connect (priv->isearch_entry, "activate", -+ G_CALLBACK (isearch_activate_event), slot); -+ -+ g_signal_connect (G_OBJECT (priv->isearch_entry), "preedit-changed", -+ G_CALLBACK (isearch_preedit_changed), slot); -+ gtk_container_add (GTK_CONTAINER (vbox), priv->isearch_entry); -+ -+ gtk_widget_realize (priv->isearch_entry); -+} -+ -+static gboolean -+isearch_timeout (gpointer user_data) -+{ -+ NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (user_data); -+ -+ if (!g_source_is_destroyed (g_main_current_source ())) -+ isearch_hide (slot, NULL); -+ -+ return FALSE; -+} -+ -+static void -+isearch_timeout_destroy (gpointer user_data) -+{ -+ NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (user_data); -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ priv->isearch_timeout_id = 0; -+} -+ -+static void -+isearch_timeout_restart (NautilusWindowSlot *slot) -+{ -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ if (priv->isearch_timeout_id != 0) -+ { -+ g_source_remove (priv->isearch_timeout_id); -+ -+ priv->isearch_timeout_id = -+ gdk_threads_add_timeout_full (G_PRIORITY_LOW, ISEARCH_TIMEOUT, -+ isearch_timeout, slot, -+ isearch_timeout_destroy); -+ } -+} -+ -+static gboolean -+isearch_window_delete_event (GtkWidget *widget, -+ GdkEventAny *event, -+ NautilusWindowSlot *slot) -+{ -+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); -+ -+ isearch_hide (slot, NULL); -+ return TRUE; -+} -+ -+static gboolean -+isearch_window_button_press_event (GtkWidget *widget, -+ GdkEventButton *event, -+ NautilusWindowSlot *slot) -+{ -+ GdkDevice *keyb_device; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); -+ -+ keyb_device = gdk_device_get_associated_device (event->device); -+ isearch_hide (slot, keyb_device); -+ -+ /* A bit of hackery here */ -+ if (NAUTILUS_IS_CANVAS_VIEW (priv->content_view)) -+ { -+ NautilusCanvasContainer *cc = nautilus_canvas_view_get_canvas_container ( -+ NAUTILUS_CANVAS_VIEW (priv->content_view)); -+ gboolean retval = FALSE; -+ -+ if (event->window == gtk_layout_get_bin_window (GTK_LAYOUT (cc))) -+ g_signal_emit_by_name (GTK_WIDGET (cc), "button-press-event", event, -+ &retval); -+ -+ return retval; -+ } -+ else if (NAUTILUS_IS_LIST_VIEW (priv->content_view)) -+ { -+ gboolean retval = FALSE; -+ // NautilusListView *lv = NAUTILUS_LIST_VIEW (priv->content_view); -+ GtkTreeView *tv = -+ nautilus_list_view_get_tree_view (NAUTILUS_LIST_VIEW (priv->content_view)); -+ -+ if (event->window == gtk_tree_view_get_bin_window (tv)) -+ g_signal_emit_by_name (GTK_WIDGET (tv), -+ "button-press-event", -+ event, -+ &retval); -+ -+ return retval; -+ } -+ -+ return TRUE; -+} -+ -+static gboolean -+isearch_window_scroll_event (GtkWidget *widget, -+ GdkEventScroll *event, -+ NautilusWindowSlot *slot) -+{ -+ gboolean retval = FALSE; -+ -+ if (event->direction == GDK_SCROLL_UP) -+ { -+ isearch_move_prev (slot); -+ retval = TRUE; -+ } -+ else if (event->direction == GDK_SCROLL_DOWN) -+ { -+ isearch_move_next (slot); -+ retval = TRUE; -+ } -+ -+ if (retval) -+ isearch_timeout_restart (slot); -+ -+ return retval; -+} -+ -+static void -+isearch_activate_items_alternate (NautilusWindowSlot *slot) -+{ -+ GList *file_list; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ file_list = nautilus_view_get_selection (priv->content_view); -+ nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (priv->content_view), -+ file_list, -+ NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB, TRUE); -+ nautilus_file_list_free (file_list); -+} -+ -+static gboolean -+isearch_window_key_press_event (GtkWidget *widget, -+ GdkEventKey *event, -+ NautilusWindowSlot *slot) -+{ -+ GdkModifierType default_accel; -+ gboolean retval = FALSE; -+ -+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); -+ g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot), FALSE); -+ -+ /* close window and cancel the search */ -+ if (event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_Tab || -+ event->keyval == GDK_KEY_KP_Tab || event->keyval == GDK_KEY_ISO_Left_Tab) -+ { -+ -+ isearch_hide (slot, gdk_event_get_device ((GdkEvent *) event)); -+ return TRUE; -+ } -+ -+ default_accel = -+ gtk_widget_get_modifier_mask (widget, -+ GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR); -+ -+ /* select previous matching iter */ -+ if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) -+ { -+ if (!isearch_move_prev (slot)) -+ gtk_widget_error_bell (widget); -+ -+ retval = TRUE; -+ } -+ if (((event->state & (default_accel | GDK_SHIFT_MASK)) == -+ (default_accel | GDK_SHIFT_MASK)) && -+ (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) -+ { -+ if (!isearch_move_prev (slot)) -+ gtk_widget_error_bell (widget); -+ -+ retval = TRUE; -+ } -+ /* select next matching iter */ -+ if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) -+ { -+ if (!isearch_move_next (slot)) -+ gtk_widget_error_bell (widget); -+ -+ retval = TRUE; -+ } -+ if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel) && -+ (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) -+ { -+ if (!isearch_move_next (slot)) -+ gtk_widget_error_bell (widget); -+ -+ retval = TRUE; -+ } -+ -+ /* Alternate activation (ShiftEnter). -+ * Regular activation (Enter) is handled by the entry activate signal. -+ */ -+ if ((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) && -+ (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) -+ { -+ isearch_activate_items_alternate (slot); -+ isearch_hide (slot, gdk_event_get_device ((GdkEvent *) event)); -+ retval = TRUE; -+ } -+ isearch_timeout_restart (slot); -+ return retval; -+} -+ -+static void -+isearch_disable_hide (GtkEntry *entry, -+ GtkMenu *menu, -+ gpointer data) -+{ -+ NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (data); -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ priv->isearch_disable_hide = 1; -+ g_signal_connect (menu, "hide", G_CALLBACK (isearch_enable_hide), data); -+} -+ -+static void -+isearch_preedit_changed (GtkEntry *entry, -+ gchar *preedit, -+ NautilusWindowSlot *slot) -+{ -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ priv->isearch_imcontext_changed = 1; -+ isearch_timeout_restart (slot); -+} -+ -+static void -+isearch_activate_event (GtkEntry *entry, -+ NautilusWindowSlot *slot) -+{ -+ // GtkTreePath *path; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ isearch_hide (slot, gtk_get_current_event_device ()); -+ nautilus_files_view_activate_selection (NAUTILUS_FILES_VIEW (priv->content_view)); -+} -+ + +static gboolean -+isearch_enable_hide_real (gpointer data) -+{ -+ NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (data); -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ priv->isearch_disable_hide = 0; -+ return FALSE; -+} -+ -+static void -+isearch_enable_hide (GtkWidget *widget, -+ gpointer data) -+{ -+ gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, -+ isearch_enable_hide_real, -+ g_object_ref (data), -+ g_object_unref); -+} -+ -+static void -+send_focus_change (GtkWidget *widget, -+ GdkDevice *device, -+ gboolean in) -+{ -+ GdkDeviceManager *device_manager; -+ GList *devices; -+ GList *d; -+ -+ device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget)); -+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER); -+ devices = g_list_concat (devices, -+ gdk_device_manager_list_devices (device_manager, -+ GDK_DEVICE_TYPE_SLAVE)); -+ devices = g_list_concat (devices, -+ gdk_device_manager_list_devices (device_manager, -+ GDK_DEVICE_TYPE_FLOATING)); -+ -+ for (d = devices; d; d = d->next) -+ { -+ GdkDevice *dev = d->data; -+ GdkEvent *fevent; -+ GdkWindow *window; -+ -+ if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) -+ continue; -+ -+ window = gtk_widget_get_window (widget); -+ -+ /* Skip non-master keyboards that haven't -+ * selected for events from this window -+ */ -+ if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER && -+ !gdk_window_get_device_events (window, dev)) -+ continue; -+ -+ fevent = gdk_event_new (GDK_FOCUS_CHANGE); -+ -+ fevent->focus_change.type = GDK_FOCUS_CHANGE; -+ fevent->focus_change.window = g_object_ref (window); -+ fevent->focus_change.in = in; -+ gdk_event_set_device (fevent, device); -+ -+ gtk_widget_send_focus_change (widget, fevent); -+ -+ gdk_event_free (fevent); -+ } -+ -+ g_list_free (devices); -+} -+ -+static void -+isearch_hide (NautilusWindowSlot *slot, -+ GdkDevice *device) ++type_ahead_search (void) +{ -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ if (priv->isearch_disable_hide) -+ return; -+ -+ if (!priv->isearch_enable) -+ return; -+ -+ if (priv->isearch_entry_changed_id) -+ { -+ g_signal_handler_disconnect (priv->isearch_entry, -+ priv->isearch_entry_changed_id); -+ priv->isearch_entry_changed_id = 0; -+ } -+ if (priv->isearch_timeout_id) -+ { -+ g_source_remove (priv->isearch_timeout_id); -+ priv->isearch_timeout_id = 0; -+ } -+ if (priv->isearch_window != NULL && -+ gtk_widget_get_visible (priv->isearch_window)) -+ { -+ /* send focus-in event */ -+ send_focus_change (GTK_WIDGET (priv->isearch_entry), device, FALSE); -+ gtk_widget_hide (priv->isearch_window); -+ gtk_entry_set_text (GTK_ENTRY (priv->isearch_entry), ""); -+ send_focus_change (GTK_WIDGET (slot), device, TRUE); -+ } -+} -+ -+static void -+isearch_entry_changed (GtkWidget *entry, -+ NautilusWindowSlot *slot) -+{ -+ // gint ret; -+ const gchar *text; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ g_return_if_fail (GTK_IS_ENTRY (entry)); -+ g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot)); -+ -+ text = gtk_entry_get_text (GTK_ENTRY (entry)); -+ -+ /* unselect all */ -+ nautilus_view_set_selection (priv->content_view, NULL); -+ -+ isearch_timeout_restart (slot); -+ -+ if (*text == '\0') -+ return; -+ -+ isearch_set_selection (slot, isearch_find (slot, text)); ++ return g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_TYPE_AHEAD_SEARCH); +} + +static gboolean -+isearch_start (NautilusWindowSlot *slot, -+ GdkDevice *device) ++clear_query_editor_timeout_callback (NautilusWindowSlot *self) +{ -+ // GList * list; -+ // gboolean found_focus = FALSE; -+ GTypeClass *klass; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ if (!priv->isearch_enable) -+ return FALSE; -+ -+ if (priv->isearch_window != NULL && -+ gtk_widget_get_visible (priv->isearch_window)) -+ return TRUE; -+ -+ if (nautilus_files_view_get_loading (NAUTILUS_FILES_VIEW (priv->content_view))) -+ return FALSE; -+ -+ isearch_ensure (slot); -+ -+ /* done, show it */ -+ isearch_position (slot); -+ gtk_widget_show (priv->isearch_window); -+ -+ if (priv->isearch_entry_changed_id == 0) -+ { -+ priv->isearch_entry_changed_id = -+ g_signal_connect (priv->isearch_entry, "changed", -+ G_CALLBACK (isearch_entry_changed), slot); -+ } -+ -+ priv->isearch_timeout_id = -+ gdk_threads_add_timeout_full (G_PRIORITY_LOW, ISEARCH_TIMEOUT, -+ isearch_timeout, slot, -+ isearch_timeout_destroy); -+ -+ /* Grab focus without selecting all the text. */ -+ klass = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (priv->isearch_entry)); -+ (*GTK_WIDGET_CLASS (klass)->grab_focus) (priv->isearch_entry); -+ -+ /* send focus-in event */ -+ send_focus_change (priv->isearch_entry, device, TRUE); -+ -+ /* search first matching iter */ -+ isearch_entry_changed (priv->isearch_entry, slot); -+ return TRUE; -+} -+ -+static void -+isearch_position (NautilusWindowSlot *slot) -+{ -+ gint x, y; -+ gint window_x, window_y; -+ gint window_width, window_height; -+ GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (slot)); -+ GdkScreen *screen = gdk_window_get_screen (window); -+ GtkRequisition requisition; -+ gint monitor_num; -+ GdkRectangle monitor; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ monitor_num = gdk_screen_get_monitor_at_window (screen, window); -+ gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); -+ -+ gtk_widget_realize (priv->isearch_window); -+ -+ gdk_window_get_origin (window, &window_x, &window_y); -+ window_width = gdk_window_get_width (window); -+ window_height = gdk_window_get_height (window); -+ gtk_widget_get_preferred_size (priv->isearch_window, &requisition, NULL); -+ -+ if (window_x + window_width > gdk_screen_get_width (screen)) -+ x = gdk_screen_get_width (screen) - requisition.width; -+ else if (window_x + window_width - requisition.width < 0) -+ x = 0; -+ else -+ x = window_x + window_width - requisition.width; -+ -+ if (window_y + window_height + requisition.height > -+ gdk_screen_get_height (screen)) -+ y = gdk_screen_get_height (screen) - requisition.height; -+ else if (window_y + window_height < 0) /* isn't really possible ... */ -+ y = 0; -+ else -+ y = window_y + window_height; -+ -+ gtk_window_move (GTK_WINDOW (priv->isearch_window), x, y); ++ nautilus_query_editor_set_query (self->query_editor, NULL); ++ self->clear_query_editor_timeout_id = 0; ++ return G_SOURCE_REMOVE; +} + -+static gboolean -+isearch_compare_filename (const gchar *f1, -+ const gchar *f2, -+ guint length) -+{ -+ gchar *normalized_f1; -+ gchar *normalized_f2; -+ gchar *case_normalized_f1 = NULL; -+ gchar *case_normalized_f2 = NULL; -+ gboolean retval = FALSE; -+ -+ normalized_f1 = g_utf8_normalize (f1, -1, G_NORMALIZE_ALL); -+ normalized_f2 = g_utf8_normalize (f2, -1, G_NORMALIZE_ALL); -+ -+ if (G_LIKELY (normalized_f1 != NULL && normalized_f2 != NULL)) -+ { -+ case_normalized_f1 = g_utf8_casefold (normalized_f1, -1); -+ case_normalized_f2 = g_utf8_casefold (normalized_f2, -1); -+ -+ retval = (strncmp (case_normalized_f1, case_normalized_f2, length) == 0); -+ } -+ -+ g_free (normalized_f1); -+ g_free (normalized_f2); -+ g_free (case_normalized_f1); -+ g_free (case_normalized_f2); -+ return retval; -+} ++typedef struct { ++ GQuark attribute; ++ gboolean directories_first; ++ gboolean reversed; ++} FileCompareForTypeAheadContext; + +static int -+compare_files (gconstpointer a, -+ gconstpointer b, -+ gpointer callback_data) -+{ -+ NautilusFilesView *view = NAUTILUS_FILES_VIEW (callback_data); -+ NautilusFile *f1 = NAUTILUS_FILE (a); -+ NautilusFile *f2 = NAUTILUS_FILE (b); -+ -+ return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, f1, f2); -+} -+ -+static GList * -+isearch_get_sorted_files (NautilusWindowSlot *slot) -+{ -+ NautilusWindowSlotPrivate *priv = nautilus_window_slot_get_instance_private (slot); -+ NautilusView *view = priv->content_view; -+ NautilusDirectory *dir = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (view)); -+ GList *list = nautilus_directory_get_file_list (dir); -+ GList *sorted_list; -+ -+ sorted_list = g_list_sort_with_data (list, compare_files, view); -+ return sorted_list; -+} -+ -+static NautilusFile * -+isearch_find (NautilusWindowSlot *slot, -+ const gchar *text) -+{ -+ GList *files = isearch_get_sorted_files (slot); -+ GList *l; -+ NautilusFile *found = NULL; -+ -+ for (l = files; l; l = g_list_next (l)) -+ { -+ NautilusFile *file = NAUTILUS_FILE (l->data); -+ gchar *filename = nautilus_file_get_display_name (file); -+ -+ if (isearch_compare_filename (filename, text, strlen (text))) -+ found = file; -+ -+ g_free (filename); -+ -+ if (found) -+ break; -+ } -+ -+ return found; -+} -+ -+static NautilusFile * -+isearch_find_next (NautilusWindowSlot *slot, -+ const gchar *text) -+{ -+ GList *files = isearch_get_sorted_files (slot); -+ NautilusFile *found = NULL; -+ GList *current; -+ GList *l; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ current = g_list_find (files, priv->isearch_selected_file); -+ for (l = g_list_next (current); l; l = g_list_next (l)) -+ { -+ NautilusFile *file = NAUTILUS_FILE (l->data); -+ gchar *display_name = nautilus_file_get_display_name (file); -+ -+ if (isearch_compare_filename (display_name, text, strlen (text))) -+ found = file; -+ -+ g_free (display_name); -+ -+ if (found) -+ break; -+ } -+ -+ return found; -+} -+ -+static NautilusFile * -+isearch_find_prev (NautilusWindowSlot *slot, -+ const gchar *text) -+{ -+ GList *files = isearch_get_sorted_files (slot); -+ NautilusFile *found = NULL; -+ GList *current; -+ GList *l; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ current = g_list_find (files, priv->isearch_selected_file); -+ for (l = g_list_previous (current); l; l = g_list_previous (l)) -+ { -+ NautilusFile *file = NAUTILUS_FILE (l->data); -+ gchar *display_name = nautilus_file_get_display_name (file); -+ -+ if (isearch_compare_filename (display_name, text, strlen (text))) -+ found = file; -+ -+ g_free (display_name); -+ -+ if (found) -+ break; -+ } -+ -+ return found; -+} -+ -+static gboolean -+isearch_move_next (NautilusWindowSlot *slot) -+{ -+ const gchar *text; -+ NautilusFile *iter; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ text = gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry)); -+ iter = isearch_find_next (slot, text); -+ -+ if (iter) -+ isearch_set_selection (slot, iter); -+ -+ return iter != NULL; -+} -+ -+static gboolean -+isearch_move_prev (NautilusWindowSlot *slot) -+{ -+ const gchar *text; -+ NautilusFile *iter; -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ text = gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry)); -+ iter = isearch_find_prev (slot, text); -+ -+ if (iter) -+ isearch_set_selection (slot, iter); -+ -+ return iter != NULL; -+} -+ -+static void -+isearch_set_selection (NautilusWindowSlot *slot, -+ NautilusFile *file) ++file_compare_for_type_ahead (gconstpointer a, gconstpointer b, gpointer user_data) +{ -+ GList *list = NULL; -+ NautilusWindowSlotPrivate *priv; -+ -+ list = g_list_append (list, file); -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ priv->isearch_selected_file = file; -+ nautilus_view_set_selection (priv->content_view, list); -+ g_list_free (list); ++ FileCompareForTypeAheadContext *ctx = user_data; ++ return nautilus_file_compare_for_sort_by_attribute_q (NAUTILUS_FILE(a), ++ NAUTILUS_FILE(b), ++ ctx->attribute, ++ ctx->directories_first, ++ ctx->reversed); +} + -+static void -+isearch_enable_changed (gpointer callback_data) -+{ -+ NautilusWindowSlot *slot; -+ gboolean enable; -+ NautilusWindowSlotPrivate *priv; -+ -+ slot = NAUTILUS_WINDOW_SLOT (callback_data); -+ priv = nautilus_window_slot_get_instance_private (slot); -+ -+ enable = -+ g_settings_get_boolean (nautilus_preferences, -+ NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH); -+ -+ if (enable != priv->isearch_enable) -+ { -+ if (!enable) -+ isearch_dispose (slot); -+ -+ priv->isearch_enable = enable; -+ } -+} -+ -+static void -+isearch_dispose (NautilusWindowSlot *slot) -+{ -+ NautilusWindowSlotPrivate *priv; -+ -+ priv = nautilus_window_slot_get_instance_private (slot); + static void + query_editor_changed_callback (NautilusQueryEditor *editor, + NautilusQuery *query, +@@ -436,8 +468,61 @@ query_editor_changed_callback (NautilusQueryEditor *editor, + + view = nautilus_window_slot_get_current_view (self); + +- nautilus_view_set_search_query (view, query); +- nautilus_window_slot_set_location (self, nautilus_view_get_location (view)); ++ if (nautilus_window_slot_get_search_visible (self)) ++ { ++ nautilus_view_set_search_query (view, query); ++ nautilus_window_slot_set_location (self, nautilus_view_get_location (view)); ++ } ++ else ++ { ++ /* Find all files with a display name that starts with the query, case insensitive. */ ++ GFile *location = nautilus_window_slot_get_current_location (self); ++ g_autoptr (NautilusDirectory) directory = nautilus_directory_get (location); ++ const gchar *text = nautilus_query_get_text (query); ++ g_autofree gchar *text_casefold = g_utf8_casefold (text, -1); ++ g_autofree gchar *text_collate = g_utf8_collate_key_for_filename (text_casefold, -1); ++ gsize text_len = strlen (text); ++ g_autolist (NautilusFile) files = nautilus_directory_get_file_list (directory); ++ g_autolist (NautilusFile) matches = NULL; ++ GList *l; ++ ++ for (l = files; l; l = l->next) ++ { ++ NautilusFile *file = NAUTILUS_FILE (l->data); ++ g_autofree const gchar *name = nautilus_file_get_display_name (file); ++ g_autofree const gchar *name_casefold = g_utf8_casefold (name, text_len); ++ g_autofree const gchar *name_collate = g_utf8_collate_key_for_filename (name_casefold, -1); ++ ++ if (g_str_equal (name_collate, text_collate)) ++ { ++ matches = g_list_prepend (matches, nautilus_file_ref (file)); ++ } ++ } + -+ if (!priv->isearch_enable) -+ return; ++ /* Select the first match */ ++ { ++ FileCompareForTypeAheadContext ctx; ++ GActionGroup *action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (view)); ++ g_autoptr (GVariant) value = g_action_group_get_action_state (action_group, "sort"); ++ const gchar *attribute_name; ++ g_autolist (NautilusFile) selection; ++ ++ g_variant_get (value, "(&sb)", &attribute_name, &ctx.reversed); ++ ctx.attribute = g_quark_from_string (attribute_name); ++ ctx.directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (view)); ++ matches = g_list_sort_with_data (matches, file_compare_for_type_ahead, &ctx); ++ ++ selection = matches; ++ matches = g_list_remove_link (matches, selection); ++ nautilus_view_set_selection (self->content_view, selection); ++ } + -+ if (priv->isearch_entry_changed_id != 0) -+ { -+ g_signal_handler_disconnect (G_OBJECT (priv->isearch_entry), -+ priv->isearch_entry_changed_id); -+ priv->isearch_entry_changed_id = 0; -+ } -+ if (priv->isearch_timeout_id != 0) -+ { -+ g_source_remove (priv->isearch_timeout_id); -+ priv->isearch_timeout_id = 0; -+ } -+ if (priv->isearch_window != NULL) -+ { -+ gtk_widget_destroy (priv->isearch_window); -+ priv->isearch_window = NULL; -+ priv->isearch_entry = NULL; -+ } -+} ++ /* Reset timeout that clears type ahead query */ ++ g_clear_handle_id (&self->clear_query_editor_timeout_id, g_source_remove); ++ self->clear_query_editor_timeout_id = g_timeout_add (CLEAR_QUERY_EDITOR_TIMEOUT, ++ G_SOURCE_FUNC (clear_query_editor_timeout_callback), ++ self); ++ } + } + + static void +@@ -447,11 +532,6 @@ hide_query_editor (NautilusWindowSlot *self) + + view = nautilus_window_slot_get_current_view (self); + +- g_clear_signal_handler (&self->qe_changed_id, self->query_editor); +- g_clear_signal_handler (&self->qe_cancel_id, self->query_editor); +- g_clear_signal_handler (&self->qe_activated_id, self->query_editor); +- g_clear_signal_handler (&self->qe_focus_view_id, self->query_editor); +- + nautilus_query_editor_set_query (self->query_editor, NULL); + + if (nautilus_view_is_searching (view)) +@@ -515,31 +595,6 @@ show_query_editor (NautilusWindowSlot *self) + } + + gtk_widget_grab_focus (GTK_WIDGET (self->query_editor)); +- +- if (self->qe_changed_id == 0) +- { +- self->qe_changed_id = +- g_signal_connect (self->query_editor, "changed", +- G_CALLBACK (query_editor_changed_callback), self); +- } +- if (self->qe_cancel_id == 0) +- { +- self->qe_cancel_id = +- g_signal_connect (self->query_editor, "cancel", +- G_CALLBACK (query_editor_cancel_callback), self); +- } +- if (self->qe_activated_id == 0) +- { +- self->qe_activated_id = +- g_signal_connect (self->query_editor, "activated", +- G_CALLBACK (query_editor_activated_callback), self); +- } +- if (self->qe_focus_view_id == 0) +- { +- self->qe_focus_view_id = +- g_signal_connect (self->query_editor, "focus-view", +- G_CALLBACK (query_editor_focus_view_callback), self); +- } + } + + static void +@@ -634,7 +689,7 @@ nautilus_window_slot_handle_event (NautilusWindowSlot *self, + state); + } + +- if (retval) ++ if (retval && type_ahead_search ()) + { + nautilus_window_slot_set_search_visible (self, TRUE); + } +@@ -886,6 +941,15 @@ nautilus_window_slot_constructed (GObject *object) + gtk_box_append (GTK_BOX (self), extras_vbox); + + self->query_editor = NAUTILUS_QUERY_EDITOR (nautilus_query_editor_new ()); ++ g_signal_connect (self->query_editor, "changed", ++ G_CALLBACK (query_editor_changed_callback), self); ++ g_signal_connect (self->query_editor, "cancel", ++ G_CALLBACK (query_editor_cancel_callback), self); ++ g_signal_connect (self->query_editor, "activated", ++ G_CALLBACK (query_editor_activated_callback), self); ++ g_signal_connect (self->query_editor, "focus-view", ++ G_CALLBACK (query_editor_focus_view_callback), self); ++ + /* We want to keep alive the query editor betwen additions and removals on the + * UI, specifically when the toolbar adds or removes it */ + g_object_ref_sink (self->query_editor); +@@ -1972,6 +2036,9 @@ setup_view (NautilusWindowSlot *self, + + nautilus_window_slot_disconnect_content_view (self); + ++ nautilus_query_editor_set_query (self->query_editor, NULL); ++ g_clear_handle_id (&self->clear_query_editor_timeout_id, g_source_remove); ++ + self->new_content_view = view; + + nautilus_window_slot_connect_new_content_view (self); +diff --git a/src/nautilus-window.c b/src/nautilus-window.c +index 9429500c0..d9f6003e2 100644 +--- a/src/nautilus-window.c ++++ b/src/nautilus-window.c +@@ -1579,6 +1579,7 @@ const GActionEntry win_entries[] = + { "forward", action_forward }, + { "back-n", action_back_n, "u" }, + { "forward-n", action_forward_n, "u" }, ++ { "backspaceup", action_up }, + { "up", action_up }, + { "current-location-menu", action_show_current_location_menu }, + { "open-location", action_open_location, "s" }, +@@ -1644,6 +1645,7 @@ nautilus_window_initialize_actions (NautilusWindow *window) + /* Only accesible by shorcuts */ + nautilus_application_set_accelerators (app, "win.bookmark-current-location", ACCELS ("<control>d", "AddFavorite")); + nautilus_application_set_accelerator (app, "win.up", "<alt>Up"); ++ nautilus_application_set_accelerator (app, "win.backspaceup", "BackSpace"); + nautilus_application_set_accelerators (app, "win.go-home", ACCELS ("<alt>Home", "HomePage", "Start")); + nautilus_application_set_accelerator (app, "win.go-starred", "Favorites"); + nautilus_application_set_accelerator (app, "win.tab-move-left", "<shift><control>Page_Up"); +diff --git a/src/resources/ui/nautilus-preferences-window.ui b/src/resources/ui/nautilus-preferences-window.ui +index cff1c278e..8ad928908 100644 +--- a/src/resources/ui/nautilus-preferences-window.ui ++++ b/src/resources/ui/nautilus-preferences-window.ui +@@ -49,6 +49,21 @@ + <property name="visible">True</property> + </object> + </child> ++ <child> ++ <object class="AdwActionRow"> ++ <property name="activatable_widget">type_ahead_search</property> ++ <property name="subtitle_lines">0</property> ++ <property name="title" translatable="yes">Search on type ahead</property> ++ <property name="title_lines">0</property> ++ <property name="use_underline">True</property> ++ <property name="visible">True</property> ++ <child> ++ <object class="GtkSwitch" id="type_ahead_search"> ++ <property name="valign">center</property> ++ </object> ++ </child> ++ </object> ++ </child> + </object> + </child> + <child> |