Advertisement
Guest User

nautilus 3.24.1 typeahead #2

a guest
May 7th, 2017
655
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 45.78 KB | None | 0 0
  1.  
  2. diff --git a/data/org.gnome.nautilus.gschema.xml b/data/org.gnome.nautilus.gschema.xml
  3. index e162ebb42..b64e526a0 100644
  4. --- a/data/org.gnome.nautilus.gschema.xml
  5. +++ b/data/org.gnome.nautilus.gschema.xml
  6. @@ -207,6 +207,11 @@
  7.        <summary>Bulk rename utility</summary>
  8.        <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>
  9.      </key>
  10. +    <key name="enable-interactive-search" type="b">
  11. +      <default>true</default>
  12. +      <summary>Enable interactive (type-ahead) search</summary>
  13. +      <description>If set to true, enables interactive search, similar to Nautilus 3.4.</description>
  14. +    </key>
  15.      <key type="b" name="open-folder-on-dnd-hover">
  16.        <default>true</default>
  17.        <summary>Whether to open the hovered folder after a timeout when drag and drop operation</summary>
  18. diff --git a/src/nautilus-global-preferences.h b/src/nautilus-global-preferences.h
  19. index 7e52f6c77..b5b761da1 100644
  20. --- a/src/nautilus-global-preferences.h
  21. +++ b/src/nautilus-global-preferences.h
  22. @@ -164,6 +164,9 @@ typedef enum
  23.  /* Recent files */
  24.  #define NAUTILUS_PREFERENCES_RECENT_FILES_ENABLED          "remember-recent-files"
  25.  
  26. +/* Interactive search (typeahead) */
  27. +#define NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH     "enable-interactive-search"
  28. +
  29.  /* Move to trash shorcut changed dialog */
  30.  #define NAUTILUS_PREFERENCES_SHOW_MOVE_TO_TRASH_SHORTCUT_CHANGED_DIALOG "show-move-to-trash-shortcut-changed-dialog"
  31.  
  32. diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c
  33. index 0d2f54fb5..9f9a1692f 100644
  34. --- a/src/nautilus-list-view.c
  35. +++ b/src/nautilus-list-view.c
  36. @@ -2706,6 +2706,7 @@ nautilus_list_view_set_selection (NautilusFilesView *view,
  37.      GList *node;
  38.      GList *iters, *l;
  39.      NautilusFile *file;
  40. +    GtkTreePath *path = NULL;
  41.  
  42.      list_view = NAUTILUS_LIST_VIEW (view);
  43.      tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
  44. @@ -2722,10 +2723,22 @@ nautilus_list_view_set_selection (NautilusFilesView *view,
  45.          {
  46.              gtk_tree_selection_select_iter (tree_selection,
  47.                                              (GtkTreeIter *) l->data);
  48. +            if (!path)
  49. +                path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), (GtkTreeIter *) l->data);
  50.          }
  51. +
  52.          g_list_free_full (iters, g_free);
  53.      }
  54.  
  55. +    if (path) {
  56. +        gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
  57. +                                          path,
  58. +                                          list_view->details->file_name_column,
  59. +                                          GTK_CELL_RENDERER (list_view->details->file_name_cell),
  60. +                                          TRUE);
  61. +        gtk_tree_path_free (path);
  62. +    }
  63. +
  64.      g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
  65.      nautilus_files_view_notify_selection_changed (view);
  66.  }
  67. @@ -3600,3 +3613,9 @@ nautilus_list_view_new (NautilusWindowSlot *slot)
  68.                           "window-slot", slot,
  69.                           NULL);
  70.  }
  71. +
  72. +GtkTreeView *
  73. +nautilus_list_view_get_tree_view (NautilusListView *list_view)
  74. +{
  75. +  return list_view->details->tree_view;
  76. +}
  77. diff --git a/src/nautilus-list-view.h b/src/nautilus-list-view.h
  78. index f77543100..bbcb565d7 100644
  79. --- a/src/nautilus-list-view.h
  80. +++ b/src/nautilus-list-view.h
  81. @@ -3,7 +3,7 @@
  82.  
  83.     Copyright (C) 2000 Eazel, Inc.
  84.     Copyright (C) 2001 Anders Carlsson <andersca@gnu.org>
  85. -  
  86. +
  87.     The Gnome Library is free software; you can redistribute it and/or
  88.     modify it under the terms of the GNU Library General Public License as
  89.     published by the Free Software Foundation; either version 2 of the
  90. @@ -52,5 +52,6 @@ typedef struct {
  91.  
  92.  GType nautilus_list_view_get_type (void);
  93.  NautilusFilesView * nautilus_list_view_new (NautilusWindowSlot *slot);
  94. +GtkTreeView * nautilus_list_view_get_tree_view (NautilusListView *list_view);
  95.  
  96.  #endif /* NAUTILUS_LIST_VIEW_H */
  97. diff --git a/src/nautilus-preferences-window.c b/src/nautilus-preferences-window.c
  98. index 8c4f981c0..b545fc3ec 100644
  99. --- a/src/nautilus-preferences-window.c
  100. +++ b/src/nautilus-preferences-window.c
  101. @@ -59,6 +59,8 @@
  102.      "trash_confirm_checkbutton"
  103.  #define NAUTILUS_PREFERENCES_DIALOG_AUTOMATIC_DECOMPRESSION_WIDGET             \
  104.      "automatic_decompression_checkbutton"
  105. +#define NAUTILUS_PREFERENCES_DIALOG_ENABLE_INTERACTIVE_SEARCH_WIDGET           \
  106. +    "interactive_search_checkbutton"
  107.  
  108.  /* int enums */
  109.  #define NAUTILUS_PREFERENCES_DIALOG_THUMBNAIL_LIMIT_WIDGET                     \
  110. @@ -492,6 +494,9 @@ static void nautilus_preferences_window_setup(GtkBuilder *builder,
  111.      bind_builder_bool (builder, nautilus_preferences,
  112.                         NAUTILUS_PREFERENCES_DIALOG_AUTOMATIC_DECOMPRESSION_WIDGET,
  113.                         NAUTILUS_PREFERENCES_AUTOMATIC_DECOMPRESSION);
  114. +    bind_builder_bool (builder, nautilus_preferences,
  115. +                       NAUTILUS_PREFERENCES_DIALOG_ENABLE_INTERACTIVE_SEARCH_WIDGET,
  116. +                       NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH);
  117.      bind_builder_bool (builder, nautilus_list_view_preferences,
  118.                         NAUTILUS_PREFERENCES_DIALOG_LIST_VIEW_USE_TREE_WIDGET,
  119.                         NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
  120. diff --git a/src/nautilus-window-slot.c b/src/nautilus-window-slot.c
  121. index c5c94e103..67a6fd0a9 100644
  122. --- a/src/nautilus-window-slot.c
  123. +++ b/src/nautilus-window-slot.c
  124. @@ -122,6 +122,17 @@ typedef struct
  125.      GError *mount_error;
  126.      gboolean tried_mount;
  127.      gint view_mode_before_search;
  128. +
  129. +    /* Interactive search */
  130. +    gboolean      isearch_enable;
  131. +    gboolean      isearch_imcontext_changed;
  132. +    gboolean      isearch_disable_hide;
  133. +    NautilusFile *isearch_selected_file;
  134. +    GtkWidget    *isearch_window;
  135. +    GtkWidget    *isearch_entry;
  136. +    gulong        isearch_entry_changed_id;
  137. +    guint         isearch_timeout_id;
  138. +    gulong        isearch_configure_event_id;
  139.  } NautilusWindowSlotPrivate;
  140.  
  141.  G_DEFINE_TYPE_WITH_PRIVATE (NautilusWindowSlot, nautilus_window_slot, GTK_TYPE_BOX);
  142. @@ -153,6 +164,98 @@ static void trash_state_changed_cb (NautilusTrashMonitor *monitor,
  143.                                      gboolean              is_empty,
  144.                                      gpointer              user_data);
  145.  
  146. +
  147. +/* Interactive search */
  148. +static void            isearch_ensure                      (NautilusWindowSlot *slot);
  149. +
  150. +static gboolean        isearch_start                       (NautilusWindowSlot *slot,
  151. +                                                            GdkDevice          *device);
  152. +
  153. +static void            isearch_enable_changed              (gpointer            callback_data);
  154. +
  155. +static void            isearch_dispose                     (NautilusWindowSlot *slot);
  156. +
  157. +static void            isearch_hide                        (NautilusWindowSlot *slot,
  158. +                                                            GdkDevice          *device);
  159. +
  160. +static gboolean        isearch_timeout                     (gpointer            user_data);
  161. +
  162. +static void            isearch_timeout_destroy             (gpointer            user_data);
  163. +
  164. +static void            isearch_timeout_restart             (NautilusWindowSlot *slot);
  165. +
  166. +static gboolean        isearch_window_delete_event         (GtkWidget          *widget,
  167. +                                                            GdkEventAny        *event,
  168. +                                                            NautilusWindowSlot *slot);
  169. +
  170. +static gboolean        isearch_window_button_press_event   (GtkWidget          *widget,
  171. +                                                            GdkEventButton     *event,
  172. +                                                            NautilusWindowSlot *slot);
  173. +
  174. +static gboolean        isearch_window_scroll_event         (GtkWidget          *widget,
  175. +                                                            GdkEventScroll     *event,
  176. +                                                            NautilusWindowSlot *slot);
  177. +
  178. +static void            isearch_activate_items_alternate    (NautilusWindowSlot *slot);
  179. +
  180. +static gboolean        isearch_window_key_press_event      (GtkWidget          *widget,
  181. +                                                            GdkEventKey        *event,
  182. +                                                            NautilusWindowSlot *slot);
  183. +
  184. +static void            isearch_disable_hide                (GtkEntry           *entry,
  185. +                                                            GtkMenu            *menu,
  186. +                                                            gpointer            data);
  187. +
  188. +static void            isearch_preedit_changed             (GtkEntry           *entry,
  189. +                                                            gchar              *preedit,
  190. +                                                            NautilusWindowSlot *slot);
  191. +
  192. +static void            isearch_activate_event              (GtkEntry           *entry,
  193. +                                                            NautilusWindowSlot *slot);
  194. +
  195. +static gboolean        isearch_enable_hide_real            (gpointer            data);
  196. +
  197. +static void            isearch_enable_hide                 (GtkWidget          *widget,
  198. +                                                            gpointer            data);
  199. +
  200. +static void            send_focus_change                   (GtkWidget          *widget,
  201. +                                                            GdkDevice          *device,
  202. +                                                            gboolean            in);
  203. +
  204. +static void            isearch_entry_changed               (GtkWidget          *entry,
  205. +                                                            NautilusWindowSlot *slot);
  206. +
  207. +static void            isearch_position                    (NautilusWindowSlot *slot);
  208. +
  209. +static gboolean        isearch_compare_filename            (const gchar        *f1,
  210. +                                                            const gchar        *f2,
  211. +                                                            guint               length);
  212. +
  213. +static int             compare_files                       (gconstpointer       a,
  214. +                                                            gconstpointer       b,
  215. +                                                            gpointer            callback_data);
  216. +
  217. +static GList          *isearch_get_sorted_files            (NautilusWindowSlot *slot);
  218. +
  219. +static NautilusFile   *isearch_find                        (NautilusWindowSlot *slot,
  220. +                                                            const gchar        *text);
  221. +
  222. +static NautilusFile   *isearch_find_next                   (NautilusWindowSlot *slot,
  223. +                                                            const gchar        *text);
  224. +
  225. +static NautilusFile   *isearch_find_prev                   (NautilusWindowSlot *slot,
  226. +                                                            const gchar        *text);
  227. +
  228. +static gboolean        isearch_move_next                   (NautilusWindowSlot *slot);
  229. +
  230. +static gboolean        isearch_move_prev                   (NautilusWindowSlot *slot);
  231. +
  232. +static void            isearch_set_selection               (NautilusWindowSlot *slot,
  233. +                                                            NautilusFile       *file);
  234. +
  235. +#define ISEARCH_TIMEOUT    5000
  236. +
  237. +
  238.  gboolean
  239.  nautilus_window_slot_handles_location (NautilusWindowSlot *self,
  240.                                         GFile              *location)
  241. @@ -569,21 +672,86 @@ nautilus_window_slot_handle_event (NautilusWindowSlot *self,
  242.      action = g_action_map_lookup_action (G_ACTION_MAP (priv->slot_action_group),
  243.                                           "search-visible");
  244.  
  245. -    /* If the action is not enabled, don't try to handle search */
  246. -    if (g_action_get_enabled (action))
  247. -    {
  248. -        retval = gtk_search_bar_handle_event (GTK_SEARCH_BAR (priv->query_editor),
  249. -                                              (GdkEvent *) event);
  250. -    }
  251. +    if (priv->isearch_enable) {
  252. +        GdkEvent    *new_event;
  253. +        gchar       *old_text;
  254. +        const gchar *new_text;
  255. +        GdkScreen   *screen;
  256. +        gboolean     text_modified;
  257. +        gulong       popup_menu_id;
  258. +
  259. +        isearch_ensure (self);
  260. +
  261. +        /* Make a copy of the current text */
  262. +        old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry)));
  263. +        new_event = gdk_event_copy ((GdkEvent *) event);
  264. +        g_object_unref (((GdkEventKey *) new_event)->window);
  265. +
  266. +        ((GdkEventKey *) new_event)->window =
  267. +                g_object_ref (gtk_widget_get_window (priv->isearch_window));
  268. +        gtk_widget_realize (priv->isearch_window);
  269. +
  270. +        popup_menu_id = g_signal_connect (priv->isearch_entry,
  271. +                                          "popup-menu", G_CALLBACK (gtk_true),
  272. +                                          NULL);
  273. +
  274. +        /* Move the entry off screen */
  275. +        screen = gtk_widget_get_screen (GTK_WIDGET (self));
  276. +        gtk_window_move (GTK_WINDOW (priv->isearch_window),
  277. +                         gdk_screen_get_width (screen) + 1,
  278. +                         gdk_screen_get_height (screen) + 1);
  279. +        gtk_widget_show (priv->isearch_window);
  280. +
  281. +        /* Send the event to the window.  If the preedit_changed signal is emitted during this
  282. +         * event, we will set priv->imcontext_changed  */
  283. +        priv->isearch_imcontext_changed = FALSE;
  284. +        retval = gtk_widget_event (priv->isearch_window, new_event);
  285. +        gdk_event_free (new_event);
  286. +        gtk_widget_hide (priv->isearch_window);
  287. +
  288. +        g_signal_handler_disconnect (priv->isearch_entry, popup_menu_id);
  289. +
  290. +        /* We check to make sure that the entry tried to handle the text, and that the text has
  291. +         * changed. */
  292. +        new_text = gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry));
  293. +        text_modified = strcmp (old_text, new_text) != 0;
  294. +        g_free (old_text);
  295. +
  296. +        if (priv->isearch_imcontext_changed || (retval && text_modified)) {
  297. +            if (isearch_start (self, gdk_event_get_device ((GdkEvent *) event))) {
  298. +                gtk_widget_grab_focus (GTK_WIDGET (self));
  299. +                return TRUE;
  300. +            }
  301.  
  302. -    if (retval)
  303. -    {
  304. -        nautilus_window_slot_set_search_visible (self, TRUE);
  305. +            gtk_entry_set_text (GTK_ENTRY (priv->isearch_entry), "");
  306. +            return FALSE;
  307. +        }
  308. +    } else {
  309. +        /* If the action is not enabled, don't try to handle search */
  310. +        if (g_action_get_enabled (action))
  311. +        {
  312. +            retval = gtk_search_bar_handle_event (GTK_SEARCH_BAR (priv->query_editor),
  313. +                                                  (GdkEvent *) event);
  314. +        }
  315. +
  316. +        if (retval)
  317. +        {
  318. +            nautilus_window_slot_set_search_visible (self, TRUE);
  319. +        }
  320.      }
  321.  
  322.      return retval;
  323.  }
  324.  
  325. +/* static gboolean
  326. +configure_event_cb (GtkWidget          *widget,
  327. +                    GdkEventConfigure  *event,
  328. +                    NautilusWindowSlot *slot)
  329. +{
  330. +    isearch_hide (slot, NULL);
  331. +    return FALSE;
  332. +} */
  333. +
  334.  static void
  335.  real_active (NautilusWindowSlot *self)
  336.  {
  337. @@ -612,10 +780,19 @@ static void
  338.  real_inactive (NautilusWindowSlot *self)
  339.  {
  340.      NautilusWindow *window;
  341. +    NautilusWindowSlotPrivate *priv;
  342.  
  343. +    priv = nautilus_window_slot_get_instance_private (self);
  344.      window = nautilus_window_slot_get_window (self);
  345.      g_assert (self == nautilus_window_get_active_slot (window));
  346.  
  347. +    isearch_hide (self, NULL);
  348. +    if (priv->isearch_configure_event_id != 0) {
  349. +        g_signal_handler_disconnect (GTK_WIDGET (priv->window),
  350. +                                     priv->isearch_configure_event_id);
  351. +        priv->isearch_configure_event_id = 0;
  352. +    }
  353. +
  354.      gtk_widget_insert_action_group (GTK_WIDGET (window), "slot", NULL);
  355.  }
  356.  
  357. @@ -908,9 +1085,30 @@ nautilus_window_slot_init (NautilusWindowSlot *self)
  358.      nautilus_application_set_accelerator (app, "slot.files-view-mode(uint32 0)", "<control>2");
  359.      nautilus_application_set_accelerator (app, "slot.search-visible", "<control>f");
  360.  
  361. +    priv->isearch_enable = g_settings_get_boolean (nautilus_preferences,
  362. +                                                   NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH);
  363. +
  364. +    g_signal_connect_swapped (nautilus_preferences,
  365. +                              "changed::" NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH,
  366. +                              G_CALLBACK (isearch_enable_changed),
  367. +                              self);
  368. +
  369.      priv->view_mode_before_search = NAUTILUS_VIEW_INVALID_ID;
  370.  }
  371.  
  372. +static void
  373. +nautilus_window_slot_finalize (GObject *object)
  374. +{
  375. +    NautilusWindowSlot *slot;
  376. +    slot = NAUTILUS_WINDOW_SLOT (object);
  377. +
  378. +    g_signal_handlers_disconnect_by_func (nautilus_preferences,
  379. +                                          isearch_enable_changed,
  380. +                                          slot);
  381. +
  382. +    G_OBJECT_CLASS (nautilus_window_slot_parent_class)->finalize (object);
  383. +}
  384. +
  385.  #define DEBUG_FLAG NAUTILUS_DEBUG_WINDOW
  386.  #include "nautilus-debug.h"
  387.  
  388. @@ -2687,6 +2885,7 @@ nautilus_window_slot_dispose (GObject *object)
  389.  
  390.      self = NAUTILUS_WINDOW_SLOT (object);
  391.      priv = nautilus_window_slot_get_instance_private (self);
  392. +    isearch_dispose (self);
  393.  
  394.      nautilus_window_slot_clear_forward_list (self);
  395.      nautilus_window_slot_clear_back_list (self);
  396. @@ -2777,6 +2976,7 @@ nautilus_window_slot_class_init (NautilusWindowSlotClass *klass)
  397.      oclass->constructed = nautilus_window_slot_constructed;
  398.      oclass->set_property = nautilus_window_slot_set_property;
  399.      oclass->get_property = nautilus_window_slot_get_property;
  400. +    oclass->finalize = nautilus_window_slot_finalize;
  401.  
  402.      widget_class->grab_focus = nautilus_window_slot_grab_focus;
  403.  
  404. @@ -3198,3 +3398,792 @@ nautilus_window_slot_get_loading (NautilusWindowSlot *self)
  405.  
  406.      return priv->loading;
  407.  }
  408. +
  409. +/* Interactive search */
  410. +static void
  411. +isearch_ensure (NautilusWindowSlot *slot)
  412. +{
  413. +  GtkWidget                 *frame;
  414. +  GtkWidget                 *vbox;
  415. +  GtkWidget                 *toplevel;
  416. +  GdkScreen                 *screen;
  417. +  NautilusWindowSlotPrivate *priv;
  418. +
  419. +  priv = nautilus_window_slot_get_instance_private (slot);
  420. +
  421. +  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (slot));
  422. +  screen = gtk_widget_get_screen (GTK_WIDGET (slot));
  423. +
  424. +  if (priv->isearch_window != NULL)
  425. +  {
  426. +    if (gtk_window_has_group (GTK_WINDOW (toplevel)))
  427. +      gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
  428. +                                   GTK_WINDOW (priv->isearch_window));
  429. +    else if (gtk_window_has_group (GTK_WINDOW (priv->isearch_window)))
  430. +      gtk_window_group_remove_window (gtk_window_get_group (
  431. +                                          GTK_WINDOW (priv->isearch_window)),
  432. +                                      GTK_WINDOW (priv->isearch_window));
  433. +
  434. +    gtk_window_set_screen (GTK_WINDOW (priv->isearch_window), screen);
  435. +    return;
  436. +  }
  437. +
  438. +  priv->isearch_window = gtk_window_new (GTK_WINDOW_POPUP);
  439. +  gtk_window_set_screen (GTK_WINDOW (priv->isearch_window), screen);
  440. +
  441. +  if (gtk_window_has_group (GTK_WINDOW (toplevel)))
  442. +    gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
  443. +                                 GTK_WINDOW (priv->isearch_window));
  444. +
  445. +  gtk_window_set_type_hint (GTK_WINDOW (priv->isearch_window),
  446. +                            GDK_WINDOW_TYPE_HINT_UTILITY);
  447. +  gtk_window_set_modal (GTK_WINDOW (priv->isearch_window), TRUE);
  448. +  g_signal_connect (priv->isearch_window, "delete-event",
  449. +                    G_CALLBACK (isearch_window_delete_event), slot);
  450. +  g_signal_connect (priv->isearch_window, "key-press-event",
  451. +                    G_CALLBACK (isearch_window_key_press_event), slot);
  452. +  g_signal_connect (priv->isearch_window, "button-press-event",
  453. +                    G_CALLBACK (isearch_window_button_press_event), slot);
  454. +  g_signal_connect (priv->isearch_window, "scroll-event",
  455. +                    G_CALLBACK (isearch_window_scroll_event), slot);
  456. +
  457. +  frame = gtk_frame_new (NULL);
  458. +  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  459. +  gtk_widget_show (frame);
  460. +  gtk_container_add (GTK_CONTAINER (priv->isearch_window), frame);
  461. +
  462. +  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
  463. +  gtk_widget_show (vbox);
  464. +  gtk_container_add (GTK_CONTAINER (frame), vbox);
  465. +  gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
  466. +
  467. +  /* add entry */
  468. +  priv->isearch_entry = gtk_entry_new ();
  469. +  gtk_widget_show (priv->isearch_entry);
  470. +  g_signal_connect (priv->isearch_entry, "populate-popup",
  471. +                    G_CALLBACK (isearch_disable_hide), slot);
  472. +  g_signal_connect (priv->isearch_entry, "activate",
  473. +                    G_CALLBACK (isearch_activate_event), slot);
  474. +
  475. +  g_signal_connect (G_OBJECT (priv->isearch_entry), "preedit-changed",
  476. +                    G_CALLBACK (isearch_preedit_changed), slot);
  477. +  gtk_container_add (GTK_CONTAINER (vbox), priv->isearch_entry);
  478. +
  479. +  gtk_widget_realize (priv->isearch_entry);
  480. +}
  481. +
  482. +static gboolean
  483. +isearch_timeout (gpointer user_data)
  484. +{
  485. +  NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (user_data);
  486. +
  487. +  if (!g_source_is_destroyed (g_main_current_source ()))
  488. +    isearch_hide (slot, NULL);
  489. +
  490. +  return FALSE;
  491. +}
  492. +
  493. +static void
  494. +isearch_timeout_destroy (gpointer user_data)
  495. +{
  496. +  NautilusWindowSlot        *slot = NAUTILUS_WINDOW_SLOT (user_data);
  497. +  NautilusWindowSlotPrivate *priv;
  498. +
  499. +  priv = nautilus_window_slot_get_instance_private (slot);
  500. +  priv->isearch_timeout_id = 0;
  501. +}
  502. +
  503. +static void
  504. +isearch_timeout_restart (NautilusWindowSlot *slot)
  505. +{
  506. +  NautilusWindowSlotPrivate *priv;
  507. +
  508. +  priv = nautilus_window_slot_get_instance_private (slot);
  509. +  if (priv->isearch_timeout_id != 0)
  510. +  {
  511. +    g_source_remove (priv->isearch_timeout_id);
  512. +
  513. +    priv->isearch_timeout_id =
  514. +        gdk_threads_add_timeout_full (G_PRIORITY_LOW, ISEARCH_TIMEOUT,
  515. +                                      isearch_timeout, slot,
  516. +                                      isearch_timeout_destroy);
  517. +  }
  518. +}
  519. +
  520. +static gboolean
  521. +isearch_window_delete_event (GtkWidget          *widget,
  522. +                             GdkEventAny        *event,
  523. +                             NautilusWindowSlot *slot)
  524. +{
  525. +  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
  526. +
  527. +  isearch_hide (slot, NULL);
  528. +  return TRUE;
  529. +}
  530. +
  531. +static gboolean
  532. +isearch_window_button_press_event (GtkWidget          *widget,
  533. +                                   GdkEventButton     *event,
  534. +                                   NautilusWindowSlot *slot)
  535. +{
  536. +  GdkDevice                 *keyb_device;
  537. +  NautilusWindowSlotPrivate *priv;
  538. +
  539. +  priv = nautilus_window_slot_get_instance_private (slot);
  540. +
  541. +  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
  542. +
  543. +  keyb_device = gdk_device_get_associated_device (event->device);
  544. +  isearch_hide (slot, keyb_device);
  545. +
  546. +  /* A bit of hackery here */
  547. +  if (NAUTILUS_IS_CANVAS_VIEW (priv->content_view))
  548. +  {
  549. +    NautilusCanvasContainer *cc = nautilus_canvas_view_get_canvas_container (
  550. +        NAUTILUS_CANVAS_VIEW (priv->content_view));
  551. +    gboolean retval;
  552. +
  553. +    if (event->window == gtk_layout_get_bin_window (GTK_LAYOUT (cc)))
  554. +      g_signal_emit_by_name (GTK_WIDGET (cc), "button-press-event", event,
  555. +                             &retval);
  556. +
  557. +    return retval;
  558. +  }
  559. +  else if (NAUTILUS_IS_LIST_VIEW (priv->content_view))
  560. +  {
  561. +    gboolean          retval;
  562. +    // NautilusListView *lv = NAUTILUS_LIST_VIEW (priv->content_view);
  563. +    GtkTreeView      *tv =
  564. +        nautilus_list_view_get_tree_view (NAUTILUS_LIST_VIEW (priv->content_view));
  565. +
  566. +    if (event->window == gtk_tree_view_get_bin_window (tv))
  567. +      g_signal_emit_by_name (GTK_WIDGET (tv),
  568. +                             "button-press-event",
  569. +                             event,
  570. +                             &retval);
  571. +
  572. +    return retval;
  573. +  }
  574. +
  575. +  return TRUE;
  576. +}
  577. +
  578. +static gboolean
  579. +isearch_window_scroll_event (GtkWidget          *widget,
  580. +                             GdkEventScroll     *event,
  581. +                             NautilusWindowSlot *slot)
  582. +{
  583. +  gboolean retval = FALSE;
  584. +
  585. +  if (event->direction == GDK_SCROLL_UP)
  586. +  {
  587. +    isearch_move_prev (slot);
  588. +    retval = TRUE;
  589. +  }
  590. +  else if (event->direction == GDK_SCROLL_DOWN)
  591. +  {
  592. +    isearch_move_next (slot);
  593. +    retval = TRUE;
  594. +  }
  595. +
  596. +  if (retval)
  597. +    isearch_timeout_restart (slot);
  598. +
  599. +  return retval;
  600. +}
  601. +
  602. +static void
  603. +isearch_activate_items_alternate (NautilusWindowSlot *slot)
  604. +{
  605. +  GList                     *file_list;
  606. +  NautilusWindowSlotPrivate *priv;
  607. +
  608. +  priv = nautilus_window_slot_get_instance_private (slot);
  609. +
  610. +  file_list = nautilus_view_get_selection (priv->content_view);
  611. +  nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (priv->content_view),
  612. +                                      file_list,
  613. +                                      NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB, TRUE);
  614. +  nautilus_file_list_free (file_list);
  615. +}
  616. +
  617. +static gboolean
  618. +isearch_window_key_press_event (GtkWidget          *widget,
  619. +                                GdkEventKey        *event,
  620. +                                NautilusWindowSlot *slot)
  621. +{
  622. +  GdkModifierType default_accel;
  623. +  gboolean        retval = FALSE;
  624. +
  625. +  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
  626. +  g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot), FALSE);
  627. +
  628. +  /* close window and cancel the search */
  629. +  if (event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_Tab ||
  630. +      event->keyval == GDK_KEY_KP_Tab || event->keyval == GDK_KEY_ISO_Left_Tab)
  631. +  {
  632. +
  633. +    isearch_hide (slot, gdk_event_get_device ((GdkEvent *) event));
  634. +    return TRUE;
  635. +  }
  636. +
  637. +  default_accel =
  638. +      gtk_widget_get_modifier_mask (widget,
  639. +                                    GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
  640. +
  641. +  /* select previous matching iter */
  642. +  if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
  643. +  {
  644. +    if (!isearch_move_prev (slot))
  645. +      gtk_widget_error_bell (widget);
  646. +
  647. +    retval = TRUE;
  648. +  }
  649. +  if (((event->state & (default_accel | GDK_SHIFT_MASK)) ==
  650. +       (default_accel | GDK_SHIFT_MASK)) &&
  651. +      (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
  652. +  {
  653. +    if (!isearch_move_prev (slot))
  654. +      gtk_widget_error_bell (widget);
  655. +
  656. +    retval = TRUE;
  657. +  }
  658. +  /* select next matching iter */
  659. +  if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
  660. +  {
  661. +    if (!isearch_move_next (slot))
  662. +      gtk_widget_error_bell (widget);
  663. +
  664. +    retval = TRUE;
  665. +  }
  666. +  if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel) &&
  667. +      (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
  668. +  {
  669. +    if (!isearch_move_next (slot))
  670. +      gtk_widget_error_bell (widget);
  671. +
  672. +    retval = TRUE;
  673. +  }
  674. +
  675. +  /* Alternate activation (ShiftEnter).
  676. +   * Regular activation (Enter) is handled by the entry activate signal.
  677. +   */
  678. +  if ((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) &&
  679. +      (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
  680. +  {
  681. +    isearch_activate_items_alternate (slot);
  682. +    isearch_hide (slot, gdk_event_get_device ((GdkEvent *) event));
  683. +    retval = TRUE;
  684. +  }
  685. +  isearch_timeout_restart (slot);
  686. +  return retval;
  687. +}
  688. +
  689. +static void
  690. +isearch_disable_hide (GtkEntry *entry,
  691. +                      GtkMenu  *menu,
  692. +                      gpointer  data)
  693. +{
  694. +  NautilusWindowSlot        *slot = NAUTILUS_WINDOW_SLOT (data);
  695. +  NautilusWindowSlotPrivate *priv;
  696. +
  697. +  priv = nautilus_window_slot_get_instance_private (slot);
  698. +
  699. +  priv->isearch_disable_hide = 1;
  700. +  g_signal_connect (menu, "hide", G_CALLBACK (isearch_enable_hide), data);
  701. +}
  702. +
  703. +static void
  704. +isearch_preedit_changed (GtkEntry           *entry,
  705. +                         gchar              *preedit,
  706. +                         NautilusWindowSlot *slot)
  707. +{
  708. +  NautilusWindowSlotPrivate *priv;
  709. +
  710. +  priv = nautilus_window_slot_get_instance_private (slot);
  711. +  priv->isearch_imcontext_changed = 1;
  712. +  isearch_timeout_restart (slot);
  713. +}
  714. +
  715. +static void
  716. +isearch_activate_event (GtkEntry           *entry,
  717. +                        NautilusWindowSlot *slot)
  718. +{
  719. +  // GtkTreePath               *path;
  720. +  NautilusWindowSlotPrivate *priv;
  721. +
  722. +  priv = nautilus_window_slot_get_instance_private (slot);
  723. +
  724. +  isearch_hide (slot, gtk_get_current_event_device ());
  725. +  nautilus_files_view_activate_selection (NAUTILUS_FILES_VIEW (priv->content_view));
  726. +}
  727. +
  728. +static gboolean
  729. +isearch_enable_hide_real (gpointer data)
  730. +{
  731. +  NautilusWindowSlot        *slot = NAUTILUS_WINDOW_SLOT (data);
  732. +  NautilusWindowSlotPrivate *priv;
  733. +
  734. +  priv = nautilus_window_slot_get_instance_private (slot);
  735. +  priv->isearch_disable_hide = 0;
  736. +  return FALSE;
  737. +}
  738. +
  739. +static void
  740. +isearch_enable_hide (GtkWidget *widget,
  741. +                     gpointer   data)
  742. +{
  743. +  gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200,
  744. +                                isearch_enable_hide_real,
  745. +                                g_object_ref (data),
  746. +                                g_object_unref);
  747. +}
  748. +
  749. +static void
  750. +send_focus_change (GtkWidget *widget,
  751. +                   GdkDevice *device,
  752. +                   gboolean   in)
  753. +{
  754. +  GdkDeviceManager *device_manager;
  755. +  GList            *devices;
  756. +  GList            *d;
  757. +
  758. +  device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
  759. +  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
  760. +  devices = g_list_concat (devices,
  761. +                           gdk_device_manager_list_devices (device_manager,
  762. +                                                            GDK_DEVICE_TYPE_SLAVE));
  763. +  devices = g_list_concat (devices,
  764. +                           gdk_device_manager_list_devices (device_manager,
  765. +                                                            GDK_DEVICE_TYPE_FLOATING));
  766. +
  767. +  for (d = devices; d; d = d->next)
  768. +  {
  769. +    GdkDevice *dev = d->data;
  770. +    GdkEvent  *fevent;
  771. +    GdkWindow *window;
  772. +
  773. +    if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
  774. +      continue;
  775. +
  776. +    window = gtk_widget_get_window (widget);
  777. +
  778. +    /* Skip non-master keyboards that haven't
  779. +    * selected for events from this window
  780. +    */
  781. +    if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
  782. +        !gdk_window_get_device_events (window, dev))
  783. +      continue;
  784. +
  785. +    fevent = gdk_event_new (GDK_FOCUS_CHANGE);
  786. +
  787. +    fevent->focus_change.type = GDK_FOCUS_CHANGE;
  788. +    fevent->focus_change.window = g_object_ref (window);
  789. +    fevent->focus_change.in = in;
  790. +    gdk_event_set_device (fevent, device);
  791. +
  792. +    gtk_widget_send_focus_change (widget, fevent);
  793. +
  794. +    gdk_event_free (fevent);
  795. +  }
  796. +
  797. +  g_list_free (devices);
  798. +}
  799. +
  800. +static void
  801. +isearch_hide (NautilusWindowSlot *slot,
  802. +              GdkDevice          *device)
  803. +{
  804. +  NautilusWindowSlotPrivate *priv;
  805. +
  806. +  priv = nautilus_window_slot_get_instance_private (slot);
  807. +
  808. +  if (priv->isearch_disable_hide)
  809. +    return;
  810. +
  811. +  if (!priv->isearch_enable)
  812. +    return;
  813. +
  814. +  if (priv->isearch_entry_changed_id)
  815. +  {
  816. +    g_signal_handler_disconnect (priv->isearch_entry,
  817. +                                 priv->isearch_entry_changed_id);
  818. +    priv->isearch_entry_changed_id = 0;
  819. +  }
  820. +  if (priv->isearch_timeout_id)
  821. +  {
  822. +    g_source_remove (priv->isearch_timeout_id);
  823. +    priv->isearch_timeout_id = 0;
  824. +  }
  825. +  if (priv->isearch_window != NULL &&
  826. +      gtk_widget_get_visible (priv->isearch_window))
  827. +  {
  828. +    /* send focus-in event */
  829. +    send_focus_change (GTK_WIDGET (priv->isearch_entry), device, FALSE);
  830. +    gtk_widget_hide (priv->isearch_window);
  831. +    gtk_entry_set_text (GTK_ENTRY (priv->isearch_entry), "");
  832. +    send_focus_change (GTK_WIDGET (slot), device, TRUE);
  833. +  }
  834. +}
  835. +
  836. +static void
  837. +isearch_entry_changed (GtkWidget          *entry,
  838. +                       NautilusWindowSlot *slot)
  839. +{
  840. +  // gint                       ret;
  841. +  const gchar               *text;
  842. +  NautilusWindowSlotPrivate *priv;
  843. +
  844. +  priv = nautilus_window_slot_get_instance_private (slot);
  845. +
  846. +  g_return_if_fail (GTK_IS_ENTRY (entry));
  847. +  g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot));
  848. +
  849. +  text = gtk_entry_get_text (GTK_ENTRY (entry));
  850. +
  851. +  /* unselect all */
  852. +  nautilus_view_set_selection (priv->content_view, NULL);
  853. +
  854. +  isearch_timeout_restart (slot);
  855. +
  856. +  if (*text == '\0')
  857. +    return;
  858. +
  859. +  isearch_set_selection (slot, isearch_find (slot, text));
  860. +}
  861. +
  862. +static gboolean
  863. +isearch_start (NautilusWindowSlot *slot,
  864. +               GdkDevice          *device)
  865. +{
  866. +  // GList *                    list;
  867. +  // gboolean                   found_focus = FALSE;
  868. +  GTypeClass                *klass;
  869. +  NautilusWindowSlotPrivate *priv;
  870. +
  871. +  priv = nautilus_window_slot_get_instance_private (slot);
  872. +
  873. +  if (!priv->isearch_enable)
  874. +    return FALSE;
  875. +
  876. +  if (priv->isearch_window != NULL &&
  877. +      gtk_widget_get_visible (priv->isearch_window))
  878. +    return TRUE;
  879. +
  880. +  if (nautilus_files_view_get_loading (NAUTILUS_FILES_VIEW (priv->content_view)))
  881. +    return FALSE;
  882. +
  883. +  isearch_ensure (slot);
  884. +
  885. +  /* done, show it */
  886. +  isearch_position (slot);
  887. +  gtk_widget_show (priv->isearch_window);
  888. +
  889. +  if (priv->isearch_entry_changed_id == 0)
  890. +  {
  891. +    priv->isearch_entry_changed_id =
  892. +        g_signal_connect (priv->isearch_entry, "changed",
  893. +                          G_CALLBACK (isearch_entry_changed), slot);
  894. +  }
  895. +
  896. +  priv->isearch_timeout_id =
  897. +      gdk_threads_add_timeout_full (G_PRIORITY_LOW, ISEARCH_TIMEOUT,
  898. +                                    isearch_timeout, slot,
  899. +                                    isearch_timeout_destroy);
  900. +
  901. +  /* Grab focus without selecting all the text. */
  902. +  klass = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (priv->isearch_entry));
  903. +  (*GTK_WIDGET_CLASS (klass)->grab_focus) (priv->isearch_entry);
  904. +
  905. +  /* send focus-in event */
  906. +  send_focus_change (priv->isearch_entry, device, TRUE);
  907. +
  908. +  /* search first matching iter */
  909. +  isearch_entry_changed (priv->isearch_entry, slot);
  910. +  return TRUE;
  911. +}
  912. +
  913. +static void
  914. +isearch_position (NautilusWindowSlot *slot)
  915. +{
  916. +  gint                       x, y;
  917. +  gint                       window_x, window_y;
  918. +  gint                       window_width, window_height;
  919. +  GdkWindow                 *window = gtk_widget_get_window (GTK_WIDGET (slot));
  920. +  GdkScreen                 *screen = gdk_window_get_screen (window);
  921. +  GtkRequisition             requisition;
  922. +  gint                       monitor_num;
  923. +  GdkRectangle               monitor;
  924. +  NautilusWindowSlotPrivate *priv;
  925. +
  926. +  priv = nautilus_window_slot_get_instance_private (slot);
  927. +
  928. +  monitor_num = gdk_screen_get_monitor_at_window (screen, window);
  929. +  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
  930. +
  931. +  gtk_widget_realize (priv->isearch_window);
  932. +
  933. +  gdk_window_get_origin (window, &window_x, &window_y);
  934. +  window_width = gdk_window_get_width (window);
  935. +  window_height = gdk_window_get_height (window);
  936. +  gtk_widget_get_preferred_size (priv->isearch_window, &requisition, NULL);
  937. +
  938. +  if (window_x + window_width > gdk_screen_get_width (screen))
  939. +    x = gdk_screen_get_width (screen) - requisition.width;
  940. +  else if (window_x + window_width - requisition.width < 0)
  941. +    x = 0;
  942. +  else
  943. +    x = window_x + window_width - requisition.width;
  944. +
  945. +  if (window_y + window_height + requisition.height >
  946. +      gdk_screen_get_height (screen))
  947. +    y = gdk_screen_get_height (screen) - requisition.height;
  948. +  else if (window_y + window_height < 0) /* isn't really possible ... */
  949. +    y = 0;
  950. +  else
  951. +    y = window_y + window_height;
  952. +
  953. +  gtk_window_move (GTK_WINDOW (priv->isearch_window), x, y);
  954. +}
  955. +
  956. +static gboolean
  957. +isearch_compare_filename (const gchar *f1,
  958. +                          const gchar *f2,
  959. +                          guint        length)
  960. +{
  961. +  gchar   *normalized_f1;
  962. +  gchar   *normalized_f2;
  963. +  gchar   *case_normalized_f1 = NULL;
  964. +  gchar   *case_normalized_f2 = NULL;
  965. +  gboolean retval = FALSE;
  966. +
  967. +  normalized_f1 = g_utf8_normalize (f1, -1, G_NORMALIZE_ALL);
  968. +  normalized_f2 = g_utf8_normalize (f2, -1, G_NORMALIZE_ALL);
  969. +
  970. +  if (G_LIKELY (normalized_f1 != NULL && normalized_f2 != NULL))
  971. +  {
  972. +    case_normalized_f1 = g_utf8_casefold (normalized_f1, -1);
  973. +    case_normalized_f2 = g_utf8_casefold (normalized_f2, -1);
  974. +
  975. +    retval = (strncmp (case_normalized_f1, case_normalized_f2, length) == 0);
  976. +  }
  977. +
  978. +  g_free (normalized_f1);
  979. +  g_free (normalized_f2);
  980. +  g_free (case_normalized_f1);
  981. +  g_free (case_normalized_f2);
  982. +  return retval;
  983. +}
  984. +
  985. +static int
  986. +compare_files (gconstpointer a,
  987. +               gconstpointer b,
  988. +               gpointer      callback_data)
  989. +{
  990. +  NautilusFilesView *view = NAUTILUS_FILES_VIEW (callback_data);
  991. +  NautilusFile *f1 = NAUTILUS_FILE (a);
  992. +  NautilusFile *f2 = NAUTILUS_FILE (b);
  993. +
  994. +  return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, f1, f2);
  995. +}
  996. +
  997. +static GList *
  998. +isearch_get_sorted_files (NautilusWindowSlot *slot)
  999. +{
  1000. +  NautilusWindowSlotPrivate *priv = nautilus_window_slot_get_instance_private (slot);
  1001. +  NautilusView              *view = priv->content_view;
  1002. +  NautilusDirectory         *dir = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (view));
  1003. +  GList                     *list = nautilus_directory_get_file_list (dir);
  1004. +  GList                     *sorted_list;
  1005. +
  1006. +  sorted_list = g_list_sort_with_data (list, compare_files, view);
  1007. +  return sorted_list;
  1008. +}
  1009. +
  1010. +static NautilusFile *
  1011. +isearch_find (NautilusWindowSlot *slot,
  1012. +              const gchar        *text)
  1013. +{
  1014. +  GList        *files = isearch_get_sorted_files (slot);
  1015. +  GList        *l;
  1016. +  NautilusFile *found = NULL;
  1017. +
  1018. +  for (l = files; l; l = g_list_next (l))
  1019. +  {
  1020. +    NautilusFile *file = NAUTILUS_FILE (l->data);
  1021. +    gchar        *filename = nautilus_file_get_display_name (file);
  1022. +
  1023. +    if (isearch_compare_filename (filename, text, strlen (text)))
  1024. +      found = file;
  1025. +
  1026. +    g_free (filename);
  1027. +
  1028. +    if (found)
  1029. +      break;
  1030. +  }
  1031. +
  1032. +  return found;
  1033. +}
  1034. +
  1035. +static NautilusFile *
  1036. +isearch_find_next (NautilusWindowSlot *slot,
  1037. +                   const gchar        *text)
  1038. +{
  1039. +  GList                     *files = isearch_get_sorted_files (slot);
  1040. +  NautilusFile              *found = NULL;
  1041. +  GList                     *current;
  1042. +  GList                     *l;
  1043. +  NautilusWindowSlotPrivate *priv;
  1044. +
  1045. +  priv = nautilus_window_slot_get_instance_private (slot);
  1046. +
  1047. +  current = g_list_find (files, priv->isearch_selected_file);
  1048. +  for (l = g_list_next (current); l; l = g_list_next (l))
  1049. +  {
  1050. +    NautilusFile *file = NAUTILUS_FILE (l->data);
  1051. +    gchar        *display_name = nautilus_file_get_display_name (file);
  1052. +
  1053. +    if (isearch_compare_filename (display_name, text, strlen (text)))
  1054. +      found = file;
  1055. +
  1056. +    g_free (display_name);
  1057. +
  1058. +    if (found)
  1059. +      break;
  1060. +  }
  1061. +
  1062. +  return found;
  1063. +}
  1064. +
  1065. +static NautilusFile *
  1066. +isearch_find_prev (NautilusWindowSlot *slot,
  1067. +                   const gchar        *text)
  1068. +{
  1069. +  GList                     *files = isearch_get_sorted_files (slot);
  1070. +  NautilusFile              *found = NULL;
  1071. +  GList                     *current;
  1072. +  GList                     *l;
  1073. +  NautilusWindowSlotPrivate *priv;
  1074. +
  1075. +  priv = nautilus_window_slot_get_instance_private (slot);
  1076. +
  1077. +  current = g_list_find (files, priv->isearch_selected_file);
  1078. +  for (l = g_list_previous (current); l; l = g_list_previous (l))
  1079. +  {
  1080. +    NautilusFile *file = NAUTILUS_FILE (l->data);
  1081. +    gchar        *display_name = nautilus_file_get_display_name (file);
  1082. +
  1083. +    if (isearch_compare_filename (display_name, text, strlen (text)))
  1084. +      found = file;
  1085. +
  1086. +    g_free (display_name);
  1087. +
  1088. +    if (found)
  1089. +      break;
  1090. +  }
  1091. +
  1092. +  return found;
  1093. +}
  1094. +
  1095. +static gboolean
  1096. +isearch_move_next (NautilusWindowSlot *slot)
  1097. +{
  1098. +  const gchar               *text;
  1099. +  NautilusFile              *iter;
  1100. +  NautilusWindowSlotPrivate *priv;
  1101. +
  1102. +  priv = nautilus_window_slot_get_instance_private (slot);
  1103. +
  1104. +  text = gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry));
  1105. +  iter = isearch_find_next (slot, text);
  1106. +
  1107. +  if (iter)
  1108. +    isearch_set_selection (slot, iter);
  1109. +
  1110. +  return iter != NULL;
  1111. +}
  1112. +
  1113. +static gboolean
  1114. +isearch_move_prev (NautilusWindowSlot *slot)
  1115. +{
  1116. +  const gchar               *text;
  1117. +  NautilusFile              *iter;
  1118. +  NautilusWindowSlotPrivate *priv;
  1119. +
  1120. +  priv = nautilus_window_slot_get_instance_private (slot);
  1121. +
  1122. +  text = gtk_entry_get_text (GTK_ENTRY (priv->isearch_entry));
  1123. +  iter = isearch_find_prev (slot, text);
  1124. +
  1125. +  if (iter)
  1126. +    isearch_set_selection (slot, iter);
  1127. +
  1128. +  return iter != NULL;
  1129. +}
  1130. +
  1131. +static void
  1132. +isearch_set_selection (NautilusWindowSlot *slot,
  1133. +                       NautilusFile       *file)
  1134. +{
  1135. +  GList                     *list = NULL;
  1136. +  NautilusWindowSlotPrivate *priv;
  1137. +
  1138. +  list = g_list_append (list, file);
  1139. +  priv = nautilus_window_slot_get_instance_private (slot);
  1140. +
  1141. +  priv->isearch_selected_file = file;
  1142. +  nautilus_view_set_selection (priv->content_view, list);
  1143. +  g_list_free (list);
  1144. +}
  1145. +
  1146. +static void
  1147. +isearch_enable_changed (gpointer callback_data)
  1148. +{
  1149. +  NautilusWindowSlot        *slot;
  1150. +  gboolean                   enable;
  1151. +  NautilusWindowSlotPrivate *priv;
  1152. +
  1153. +  slot = NAUTILUS_WINDOW_SLOT (callback_data);
  1154. +  priv = nautilus_window_slot_get_instance_private (slot);
  1155. +
  1156. +  enable =
  1157. +      g_settings_get_boolean (nautilus_preferences,
  1158. +                              NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH);
  1159. +
  1160. +  if (enable != priv->isearch_enable)
  1161. +  {
  1162. +    if (!enable)
  1163. +      isearch_dispose (slot);
  1164. +
  1165. +    priv->isearch_enable = enable;
  1166. +  }
  1167. +}
  1168. +
  1169. +static void
  1170. +isearch_dispose (NautilusWindowSlot *slot)
  1171. +{
  1172. +  NautilusWindowSlotPrivate *priv;
  1173. +
  1174. +  priv = nautilus_window_slot_get_instance_private (slot);
  1175. +
  1176. +  if (!priv->isearch_enable)
  1177. +    return;
  1178. +
  1179. +  if (priv->isearch_entry_changed_id != 0)
  1180. +  {
  1181. +    g_signal_handler_disconnect (G_OBJECT (priv->isearch_entry),
  1182. +                                 priv->isearch_entry_changed_id);
  1183. +    priv->isearch_entry_changed_id = 0;
  1184. +  }
  1185. +  if (priv->isearch_timeout_id != 0)
  1186. +  {
  1187. +    g_source_remove (priv->isearch_timeout_id);
  1188. +    priv->isearch_timeout_id = 0;
  1189. +  }
  1190. +  if (priv->isearch_window != NULL)
  1191. +  {
  1192. +    gtk_widget_destroy (priv->isearch_window);
  1193. +    priv->isearch_window = NULL;
  1194. +    priv->isearch_entry = NULL;
  1195. +  }
  1196. +}
  1197. diff --git a/src/resources/ui/nautilus-preferences-window.ui b/src/resources/ui/nautilus-preferences-window.ui
  1198. index 96a2be860..b1cb7c3d0 100644
  1199. --- a/src/resources/ui/nautilus-preferences-window.ui
  1200. +++ b/src/resources/ui/nautilus-preferences-window.ui
  1201. @@ -802,6 +802,56 @@ More information will appear when zooming closer.</property>
  1202.                  <property name="position">4</property>
  1203.                </packing>
  1204.              </child>
  1205. +
  1206. +          <!-- Typeahead checkbutton BEGIN -->
  1207. +            <child>
  1208. +              <object class="GtkBox" id="vbox100">
  1209. +                <property name="visible">True</property>
  1210. +                <property name="can_focus">False</property>
  1211. +                <property name="orientation">vertical</property>
  1212. +                <property name="spacing">6</property>
  1213. +                <child>
  1214. +                  <object class="GtkLabel" id="label117">
  1215. +                    <property name="visible">True</property>
  1216. +                    <property name="can_focus">False</property>
  1217. +                    <property name="label" translatable="yes">Interactive search (typeahead)</property>
  1218. +                    <property name="xalign">0</property>
  1219. +                    <attributes>
  1220. +                      <attribute name="weight" value="bold"/>
  1221. +                    </attributes>
  1222. +                  </object>
  1223. +                  <packing>
  1224. +                    <property name="expand">False</property>
  1225. +                    <property name="fill">False</property>
  1226. +                    <property name="position">0</property>
  1227. +                  </packing>
  1228. +                </child>
  1229. +                <child>
  1230. +                  <object class="GtkCheckButton" id="interactive_search_checkbutton">
  1231. +                    <property name="label" translatable="yes">Enable interactive search</property>
  1232. +                    <property name="use_action_appearance">False</property>
  1233. +                    <property name="visible">True</property>
  1234. +                    <property name="can_focus">True</property>
  1235. +                    <property name="receives_default">False</property>
  1236. +                    <property name="use_underline">True</property>
  1237. +                    <property name="xalign">0</property>
  1238. +                    <property name="draw_indicator">True</property>
  1239. +                  </object>
  1240. +                  <packing>
  1241. +                    <property name="expand">False</property>
  1242. +                    <property name="fill">False</property>
  1243. +                    <property name="position">2</property>
  1244. +                  </packing>
  1245. +                </child>
  1246. +              </object>
  1247. +              <packing>
  1248. +                <property name="expand">False</property>
  1249. +                <property name="fill">True</property>
  1250. +                <property name="position">5</property>
  1251. +              </packing>
  1252. +            </child>
  1253. +          <!-- Typeahead checkbutton END -->
  1254. +
  1255.            </object>
  1256.            <packing>
  1257.              <property name="position">1</property>
  1258. --
  1259. 2.12.2
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement