summarylogtreecommitdiffstats
path: root/nautilus-restore-typeahead.patch
diff options
context:
space:
mode:
authorIan Hernández2015-09-28 17:07:01 -0500
committerIan Hernández2015-09-28 17:07:01 -0500
commit192c668e963104b8dc8e42364eb1fc37883611ee (patch)
tree79bbff758171cab69e424bd8df971392dd6d0b24 /nautilus-restore-typeahead.patch
parent2dd948bb1c4f5b6918d10b8f557ddb14baf1d62b (diff)
downloadaur-192c668e963104b8dc8e42364eb1fc37883611ee.tar.gz
Package updated, now using the ubuntu patch.
Diffstat (limited to 'nautilus-restore-typeahead.patch')
-rw-r--r--nautilus-restore-typeahead.patch1055
1 files changed, 1043 insertions, 12 deletions
diff --git a/nautilus-restore-typeahead.patch b/nautilus-restore-typeahead.patch
index 119086bd2a16..9c91a9942da6 100644
--- a/nautilus-restore-typeahead.patch
+++ b/nautilus-restore-typeahead.patch
@@ -1,12 +1,1043 @@
-diff -aur nautilus-3.16.2/src/nautilus-list-view.c nautilus-3.16.2.new/src/nautilus-list-view.c
---- nautilus-3.16.2/src/nautilus-list-view.c 2015-05-13 12:24:43.000000000 -0500
-+++ nautilus-3.16.2.new/src/nautilus-list-view.c 2015-09-10 18:54:11.942923502 -0500
-@@ -1923,7 +1923,7 @@
- g_str_equal,
- (GDestroyNotify) g_free,
- NULL);
-- gtk_tree_view_set_enable_search (view->details->tree_view, FALSE);
-+ gtk_tree_view_set_enable_search (view->details->tree_view, TRUE);
-
- view->details->drag_dest =
- nautilus_tree_view_drag_dest_new (view->details->tree_view);
+Description: Restore interactive search as an option
+Author: Daniel Wyatt <Daniel.Wyatt@gmail.com>
+Bug: https://bugzilla.gnome.org/show_bug.cgi?id=681871
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1164016
+
+
+---
+ libnautilus-private/nautilus-global-preferences.h | 1 +
+ .../org.gnome.nautilus.gschema.xml.in | 5 +
+ src/nautilus-list-view.c | 12 +-
+ src/nautilus-window-slot.c | 896 ++++++++++++++++++++-
+ 4 files changed, 907 insertions(+), 7 deletions(-)
+
+diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h
+index f7238b6..564bd4e 100644
+--- a/libnautilus-private/nautilus-global-preferences.h
++++ b/libnautilus-private/nautilus-global-preferences.h
+@@ -158,6 +158,7 @@ typedef enum
+ /* Recent files */
+ #define NAUTILUS_PREFERENCES_RECENT_FILES_ENABLED "remember-recent-files"
+
++#define NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH "enable-interactive-search"
+
+ /* Move to trash shorcut changed dialog */
+ #define NAUTILUS_PREFERENCES_SHOW_MOVE_TO_TRASH_SHORTCUT_CHANGED_DIALOG "show-move-to-trash-shortcut-changed-dialog"
+diff --git a/libnautilus-private/org.gnome.nautilus.gschema.xml.in b/libnautilus-private/org.gnome.nautilus.gschema.xml.in
+index eaa349d..1985fea 100644
+--- a/libnautilus-private/org.gnome.nautilus.gschema.xml.in
++++ b/libnautilus-private/org.gnome.nautilus.gschema.xml.in
+@@ -166,6 +166,11 @@
+ <_summary>Bulk rename utility</_summary>
+ <_description>If set, Nautilus will append URIs of selected files and treat the result as a command line for bulk renaming. Bulk rename applications can register themselves in this key by setting the key to a space-separated string of their executable name and any command line options. If the executable name is not set to a full path, it will be searched for in the search path.</_description>
+ </key>
++ <key name="enable-interactive-search" type="b">
++ <default>true</default>
++ <_summary>Enable interactive (type-ahead) search</_summary>
++ <_description>If set to true, enables interactive search, similar to Nautilus 3.4.</_description>
++ </key>
+ </schema>
+
+ <schema id="org.gnome.nautilus.icon-view" path="/org/gnome/nautilus/icon-view/" gettext-domain="nautilus">
+diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c
+index 39a1fc9..69e6f52 100644
+--- a/src/nautilus-list-view.c
++++ b/src/nautilus-list-view.c
+@@ -2756,6 +2756,7 @@ nautilus_list_view_set_selection (NautilusView *view, GList *selection)
+ GList *node;
+ GList *iters, *l;
+ NautilusFile *file;
++ GtkTreePath *path = NULL;
+
+ list_view = NAUTILUS_LIST_VIEW (view);
+ tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
+@@ -2770,10 +2771,19 @@ nautilus_list_view_set_selection (NautilusView *view, GList *selection)
+ for (l = iters; l != NULL; l = l->next) {
+ gtk_tree_selection_select_iter (tree_selection,
+ (GtkTreeIter *)l->data);
++ if (!path)
++ path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), (GtkTreeIter *)l->data);
+ }
+ g_list_free_full (iters, g_free);
+ }
+-
++ if (path) {
++ gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
++ path,
++ list_view->details->file_name_column,
++ GTK_CELL_RENDERER (list_view->details->file_name_cell),
++ TRUE);
++ gtk_tree_path_free (path);
++ }
+ g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
+ nautilus_view_notify_selection_changed (view);
+ }
+diff --git a/src/nautilus-window-slot.c b/src/nautilus-window-slot.c
+index 3d071fa..c30774c 100644
+--- a/src/nautilus-window-slot.c
++++ b/src/nautilus-window-slot.c
+@@ -124,6 +124,17 @@ struct NautilusWindowSlotDetails {
+ gboolean tried_mount;
+ NautilusWindowGoToCallback open_callback;
+ gpointer open_callback_user_data;
++
++ /* 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;
+ };
+
+ static guint signals[LAST_SIGNAL] = { 0 };
+@@ -134,6 +145,16 @@ static void location_has_really_changed (NautilusWindowSlot *slot);
+ static void nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *slot);
+ static void nautilus_window_slot_emit_location_change (NautilusWindowSlot *slot, GFile *from, GFile *to);
+
++/* 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);
++
++#define ISEARCH_TIMEOUT 5000
++
+ static void
+ nautilus_window_slot_sync_search_widgets (NautilusWindowSlot *slot)
+ {
+@@ -442,17 +463,86 @@ nautilus_window_slot_handle_event (NautilusWindowSlot *slot,
+
+ retval = FALSE;
+ window = nautilus_window_slot_get_window (slot);
+- if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
+- retval = nautilus_query_editor_handle_event (slot->details->query_editor, event);
+- }
+
+- if (retval) {
+- nautilus_window_slot_set_search_visible (slot, TRUE);
+- }
++ if (slot->details->isearch_enable) {
++ GdkEvent *new_event;
++ char *old_text;
++ const char *new_text;
++ gboolean retval;
++ GdkScreen *screen;
++ gboolean text_modified;
++ gulong popup_menu_id;
++
++ isearch_ensure (slot);
++
++ /* Make a copy of the current text */
++ old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (slot->details->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 (slot->details->isearch_window));
++ gtk_widget_realize (slot->details->isearch_window);
++
++ popup_menu_id = g_signal_connect (slot->details->isearch_entry,
++ "popup-menu", G_CALLBACK (gtk_true),
++ NULL);
++
++ /* Move the entry off screen */
++ screen = gtk_widget_get_screen (GTK_WIDGET (slot));
++ gtk_window_move (GTK_WINDOW (slot->details->isearch_window),
++ gdk_screen_get_width (screen) + 1,
++ gdk_screen_get_height (screen) + 1);
++ gtk_widget_show (slot->details->isearch_window);
++
++ /* Send the event to the window. If the preedit_changed signal is emitted
++ * during this event, we will set priv->imcontext_changed */
++ slot->details->isearch_imcontext_changed = FALSE;
++ retval = gtk_widget_event (slot->details->isearch_window, new_event);
++ gdk_event_free (new_event);
++ gtk_widget_hide (slot->details->isearch_window);
++
++ g_signal_handler_disconnect (slot->details->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 (slot->details->isearch_entry));
++ text_modified = strcmp (old_text, new_text) != 0;
++ g_free (old_text);
++ if (slot->details->isearch_imcontext_changed ||
++ (retval && text_modified))
++ {
++ if (isearch_start (slot,
++ gdk_event_get_device ((GdkEvent *) event))) {
++ gtk_widget_grab_focus (GTK_WIDGET (slot));
++ return TRUE;
++ }
++ else {
++ gtk_entry_set_text (GTK_ENTRY (slot->details->isearch_entry), "");
++ return FALSE;
++ }
++ }
++ } else {
++ if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
++ retval = nautilus_query_editor_handle_event (slot->details->query_editor, event);
++ }
+
++ if (retval) {
++ nautilus_window_slot_set_search_visible (slot, TRUE);
++ }
++ }
+ return retval;
+ }
+
++static gboolean
++configure_event_cb (GtkWidget *widget,
++ GdkEventConfigure *event,
++ NautilusWindowSlot *slot)
++{
++ isearch_hide (slot, NULL);
++ return FALSE;
++}
++
+ static void
+ real_active (NautilusWindowSlot *slot)
+ {
+@@ -481,6 +571,12 @@ real_inactive (NautilusWindowSlot *slot)
+
+ window = nautilus_window_slot_get_window (slot);
+ g_assert (slot == nautilus_window_get_active_slot (window));
++ isearch_hide (slot, NULL);
++ if (slot->details->isearch_configure_event_id != 0) {
++ g_signal_handler_disconnect (GTK_WIDGET (slot->details->window),
++ slot->details->isearch_configure_event_id);
++ slot->details->isearch_configure_event_id = 0;
++ }
+ }
+
+ static void
+@@ -491,6 +587,13 @@ floating_bar_action_cb (NautilusFloatingBar *floating_bar,
+ if (action == NAUTILUS_FLOATING_BAR_ACTION_ID_STOP) {
+ nautilus_window_slot_stop_loading (slot);
+ }
++ if (slot->details->isearch_configure_event_id == 0) {
++ slot->details->isearch_configure_event_id =
++ g_signal_connect (GTK_WIDGET (slot->details->window),
++ "configure-event",
++ G_CALLBACK (configure_event_cb),
++ slot);
++ }
+ }
+
+ static void
+@@ -609,6 +712,26 @@ nautilus_window_slot_init (NautilusWindowSlot *slot)
+ {
+ slot->details = G_TYPE_INSTANCE_GET_PRIVATE
+ (slot, NAUTILUS_TYPE_WINDOW_SLOT, NautilusWindowSlotDetails);
++
++ slot->details->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), slot);
++}
++
++static void
++nautilus_window_slot_finalize (GObject *object)
++{
++ NautilusWindowSlot *slot;
++
++ slot = NAUTILUS_WINDOW_SLOT (object);
++
++ g_signal_handlers_disconnect_by_func (nautilus_preferences,
++ isearch_enable_changed, slot);
++
++ G_OBJECT_CLASS (nautilus_window_slot_parent_class)->finalize (object);
+ }
+
+ static void
+@@ -2405,6 +2528,8 @@ nautilus_window_slot_dispose (GObject *object)
+
+ slot = NAUTILUS_WINDOW_SLOT (object);
+
++ isearch_dispose (slot);
++
+ nautilus_window_slot_clear_forward_list (slot);
+ nautilus_window_slot_clear_back_list (slot);
+
+@@ -2478,6 +2603,7 @@ nautilus_window_slot_class_init (NautilusWindowSlotClass *klass)
+ oclass->constructed = nautilus_window_slot_constructed;
+ oclass->set_property = nautilus_window_slot_set_property;
+ oclass->get_property = nautilus_window_slot_get_property;
++ oclass->finalize = nautilus_window_slot_finalize;
+
+ signals[ACTIVE] =
+ g_signal_new ("active",
+@@ -2833,3 +2959,761 @@ nautilus_window_slot_new (NautilusWindow *window)
+ "window", window,
+ NULL);
+ }
++
++/* Interactive search */
++
++static void
++isearch_ensure (NautilusWindowSlot *slot);
++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_hide (NautilusWindowSlot *slot,
++ GdkDevice *device);
++static void
++isearch_entry_changed (GtkWidget *entry,
++ NautilusWindowSlot *slot);
++static gboolean
++isearch_start (NautilusWindowSlot *slot, GdkDevice *device);
++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);
++static void
++isearch_enable_changed (gpointer callback_data);
++static void
++isearch_dispose (NautilusWindowSlot *slot);
++
++static void
++isearch_ensure (NautilusWindowSlot *slot)
++{
++ GtkWidget *frame, *vbox, *toplevel;
++ GdkScreen *screen;
++
++ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (slot));
++ screen = gtk_widget_get_screen (GTK_WIDGET (slot));
++
++ if (slot->details->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 (slot->details->isearch_window));
++ else if (gtk_window_has_group (GTK_WINDOW (slot->details->isearch_window)))
++ gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (slot->details->isearch_window)),
++ GTK_WINDOW (slot->details->isearch_window));
++
++ gtk_window_set_screen (GTK_WINDOW (slot->details->isearch_window), screen);
++ return;
++ }
++ slot->details->isearch_window = gtk_window_new (GTK_WINDOW_POPUP);
++ gtk_window_set_screen (GTK_WINDOW (slot->details->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 (slot->details->isearch_window));
++
++ gtk_window_set_type_hint (GTK_WINDOW (slot->details->isearch_window),
++ GDK_WINDOW_TYPE_HINT_UTILITY);
++ gtk_window_set_modal (GTK_WINDOW (slot->details->isearch_window), TRUE);
++ g_signal_connect (slot->details->isearch_window, "delete-event",
++ G_CALLBACK (isearch_window_delete_event),
++ slot);
++ g_signal_connect (slot->details->isearch_window, "key-press-event",
++ G_CALLBACK (isearch_window_key_press_event),
++ slot);
++ g_signal_connect (slot->details->isearch_window, "button-press-event",
++ G_CALLBACK (isearch_window_button_press_event),
++ slot);
++ g_signal_connect (slot->details->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 (slot->details->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 */
++ slot->details->isearch_entry = gtk_entry_new ();
++ gtk_widget_show (slot->details->isearch_entry);
++ g_signal_connect (slot->details->isearch_entry, "populate-popup",
++ G_CALLBACK (isearch_disable_hide),
++ slot);
++ g_signal_connect (slot->details->isearch_entry,
++ "activate", G_CALLBACK (isearch_activate_event),
++ slot);
++
++ g_signal_connect (G_OBJECT (slot->details->isearch_entry),
++ "preedit-changed",
++ G_CALLBACK (isearch_preedit_changed),
++ slot);
++ gtk_container_add (GTK_CONTAINER (vbox),
++ slot->details->isearch_entry);
++
++ gtk_widget_realize (slot->details->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);
++
++ slot->details->isearch_timeout_id = 0;
++}
++
++static void
++isearch_timeout_restart (NautilusWindowSlot *slot)
++{
++ if (slot->details->isearch_timeout_id != 0) {
++ g_source_remove (slot->details->isearch_timeout_id);
++
++ slot->details->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;
++
++ 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 (slot->details->content_view)) {
++ NautilusCanvasContainer *cc = nautilus_canvas_view_get_canvas_container (NAUTILUS_CANVAS_VIEW (slot->details->content_view));
++ gboolean retval;
++
++ 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 (slot->details->content_view)) {
++ NautilusListView *lv = NAUTILUS_LIST_VIEW (slot->details->content_view);
++ GtkTreeView *tv = nautilus_list_view_get_tree_view (NAUTILUS_LIST_VIEW (slot->details->content_view));
++ gboolean retval;
++
++ 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;
++
++ file_list = nautilus_view_get_selection (slot->details->content_view);
++ nautilus_view_activate_files (NAUTILUS_VIEW (slot->details->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 (Shift+Enter).
++ * 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 = (NautilusWindowSlot *)data;
++
++ slot->details->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)
++{
++ slot->details->isearch_imcontext_changed = 1;
++ isearch_timeout_restart (slot);
++}
++
++static void
++isearch_activate_event (GtkEntry *entry,
++ NautilusWindowSlot *slot)
++{
++ GtkTreePath *path;
++
++ isearch_hide (slot, gtk_get_current_event_device ());
++ nautilus_view_activate_selection (slot->details->content_view);
++}
++
++static gboolean
++isearch_enable_hide_real (gpointer data)
++{
++ NautilusWindowSlot *slot = (NautilusWindowSlot *)data;
++ slot->details->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, *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)
++{
++ if (slot->details->isearch_disable_hide)
++ return;
++
++ if (!slot->details->isearch_enable)
++ return;
++
++ if (slot->details->isearch_entry_changed_id)
++ {
++ g_signal_handler_disconnect (slot->details->isearch_entry,
++ slot->details->isearch_entry_changed_id);
++ slot->details->isearch_entry_changed_id = 0;
++ }
++ if (slot->details->isearch_timeout_id)
++ {
++ g_source_remove (slot->details->isearch_timeout_id);
++ slot->details->isearch_timeout_id = 0;
++ }
++ if (slot->details->isearch_window != NULL
++ && gtk_widget_get_visible (slot->details->isearch_window))
++ {
++ /* send focus-in event */
++ send_focus_change (GTK_WIDGET (slot->details->isearch_entry), device, FALSE);
++ gtk_widget_hide (slot->details->isearch_window);
++ gtk_entry_set_text (GTK_ENTRY (slot->details->isearch_entry), "");
++ send_focus_change (GTK_WIDGET (slot), device, TRUE);
++ }
++}
++
++static void
++isearch_entry_changed (GtkWidget *entry,
++ NautilusWindowSlot *slot)
++{
++ gint ret;
++ const gchar *text;
++
++ 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 (slot->details->content_view, NULL);
++
++ isearch_timeout_restart (slot);
++
++ if (*text == '\0')
++ return;
++
++ isearch_set_selection (slot, isearch_find (slot, text));
++}
++
++static gboolean
++isearch_start (NautilusWindowSlot *slot, GdkDevice *device)
++{
++ GTypeClass *klass;
++ GList *list;
++ gboolean found_focus = FALSE;
++
++ if (!slot->details->isearch_enable)
++ return FALSE;
++
++ if (slot->details->isearch_window != NULL &&
++ gtk_widget_get_visible (slot->details->isearch_window))
++ return TRUE;
++
++ if (nautilus_view_get_loading (slot->details->content_view))
++ return FALSE;
++
++ isearch_ensure (slot);
++
++ /* done, show it */
++ isearch_position (slot);
++ gtk_widget_show (slot->details->isearch_window);
++ if (slot->details->isearch_entry_changed_id == 0)
++ {
++ slot->details->isearch_entry_changed_id =
++ g_signal_connect (slot->details->isearch_entry, "changed",
++ G_CALLBACK (isearch_entry_changed),
++ slot);
++ }
++ slot->details->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 (slot->details->isearch_entry));
++ (*GTK_WIDGET_CLASS (klass)->grab_focus) (slot->details->isearch_entry);
++
++ /* send focus-in event */
++ send_focus_change (slot->details->isearch_entry, device, TRUE);
++
++ /* search first matching iter */
++ isearch_entry_changed (slot->details->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;
++
++ monitor_num = gdk_screen_get_monitor_at_window (screen, window);
++ gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
++
++ gtk_widget_realize (slot->details->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 (slot->details->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 (slot->details->isearch_window), x, y);
++}
++
++static gboolean
++isearch_compare_filename (const gchar *f1, const gchar *f2, guint length)
++{
++ gchar *normalized_f1;
++ gchar *normalized_f2;
++ gchar *case_normalized_f1;
++ gchar *case_normalized_f2;
++ 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;
++}
++
++static int
++compare_files (gconstpointer a, gconstpointer b, gpointer callback_data)
++{
++ NautilusView *view = NAUTILUS_VIEW (callback_data);
++ NautilusFile *f1 = NAUTILUS_FILE (a);
++ NautilusFile *f2 = NAUTILUS_FILE (b);
++
++ return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, f1, f2);
++}
++
++static GList *
++isearch_get_sorted_files (NautilusWindowSlot *slot)
++{
++ NautilusView *view = slot->details->content_view;
++ NautilusDirectory *dir = nautilus_view_get_model (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;
++
++ current = g_list_find (files, slot->details->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;
++
++ current = g_list_find (files, slot->details->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;
++
++ text = gtk_entry_get_text (GTK_ENTRY (slot->details->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;
++
++ text = gtk_entry_get_text (GTK_ENTRY (slot->details->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)
++{
++ GList *list = g_list_append (list, file);
++
++ slot->details->isearch_selected_file = file;
++ nautilus_view_set_selection (slot->details->content_view, list);
++ g_list_free (list);
++}
++
++static void
++isearch_enable_changed (gpointer callback_data)
++{
++ NautilusWindowSlot *slot;
++ gboolean enable;
++
++ slot = NAUTILUS_WINDOW_SLOT (callback_data);
++
++ enable = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH);
++
++ if (enable != slot->details->isearch_enable) {
++ if (!enable)
++ isearch_dispose (slot);
++
++ slot->details->isearch_enable = enable;
++ }
++}
++
++static void
++isearch_dispose (NautilusWindowSlot *slot)
++{
++ if (!slot->details->isearch_enable)
++ return;
++
++ if (slot->details->isearch_entry_changed_id != 0) {
++ g_signal_handler_disconnect (G_OBJECT (slot->details->isearch_entry), slot->details->isearch_entry_changed_id);
++ slot->details->isearch_entry_changed_id = 0;
++ }
++ if (slot->details->isearch_timeout_id != 0) {
++ g_source_remove (slot->details->isearch_timeout_id);
++ slot->details->isearch_timeout_id = 0;
++ }
++ if (slot->details->isearch_window != NULL) {
++ gtk_widget_destroy (slot->details->isearch_window);
++ slot->details->isearch_window = NULL;
++ slot->details->isearch_entry = NULL;
++ }
++}
+--
+2.3.4
+
+