Merge lp:~daniel-wyatt/nautilus/ubuntu into lp:~ubuntu-desktop/nautilus/ubuntu

Proposed by Daniel Wyatt
Status: Merged
Merged at revision: 412
Proposed branch: lp:~daniel-wyatt/nautilus/ubuntu
Merge into: lp:~ubuntu-desktop/nautilus/ubuntu
Diff against target: 1047 lines (+1027/-0)
3 files modified
debian/changelog (+7/-0)
debian/patches/interactive_search.patch (+1019/-0)
debian/patches/series (+1/-0)
To merge this branch: bzr merge lp:~daniel-wyatt/nautilus/ubuntu
Reviewer Review Type Date Requested Status
Robert Ancell Approve
Review via email: mp+201263@code.launchpad.net
To post a comment you must log in.
lp:~daniel-wyatt/nautilus/ubuntu updated
405. By Robert Ancell

* debian/patches/20_unity_control_center.patch:
  - Use Unity control center in Unity (LP: #1257505)

406. By Robert Ancell

* debian/patches/20_unity_control_center.patch:
  - Fix patch to handle case when u-c-c not installed

407. By Robert Ancell

* debian/patches/20_unity_control_center.patch:
  - Fix uninitialized variable

408. By Marc Deslauriers

debian/patches/no_search_on_desktop.patch: Disable search shortcut
on desktop window so a search bar doesn't appear underneath the panel.
(LP: #1176981)

409. By Marc Deslauriers

releasing 1:3.8.2-0ubuntu9

410. By Sebastien Bacher

* debian/patches/git_sidebar_state_on_start.patch:
  - correctly set the sidebar status on start (lp: #1265401)

411. By Sebastien Bacher

releasing package nautilus version 1:3.8.2-0ubuntu10

412. By Robert Ancell

Restore interactive search as an option

Revision history for this message
Robert Ancell (robert-ancell) wrote :

Merged with some changes:
- The patch was in the wrong format and didn't apply
- Missing patch header
- Merged with latest release

You should take this upstream, they are likely to take this. In general we prefer to wait for upstream to take it and backport the change. In this case due to the desire for the feature we'll take it into Ubuntu and update the patch if upstream wants it changed in their review.

I did a general review of the code:
- It's more complicated than I expected, so you might get challenged on that
- In some places you've used tab characters in place of spaces and vice versa

review: Approve
Revision history for this message
Daniel Wyatt (daniel-wyatt) wrote :

Thanks Robert!

I did take this upstream and unfortunately it was essentially rejected:
https://bugzilla.gnome.org/show_bug.cgi?id=721968

As for the code being complicated, much of it is derived from gtktreeview which has a nice type-ahead find.

Sorry about the incorrect patch format and the tab/spaces mixup.

Revision history for this message
Robert Ancell (robert-ancell) wrote :

Oh, I see. I'll ask around if there's any more symapthetic developers :)

Revision history for this message
Daniel Wyatt (daniel-wyatt) wrote :

@Robert: Thanks, I definitely hope upstream will bring type-ahead back in the long run.

Also, I let a memory leak slip by. I don't know how to update this. Do I need to create a separate merge request?
It's just a one-liner:
$ bzr diff
=== modified file 'debian/patches/interactive_search.patch'
--- debian/patches/interactive_search.patch 2014-01-22 01:51:01 +0000
+++ debian/patches/interactive_search.patch 2014-01-24 06:11:22 +0000
@@ -251,6 +251,15 @@
  }

  static void
+@@ -2415,6 +2538,8 @@
+
+ slot = NAUTILUS_WINDOW_SLOT (object);
+
++ isearch_dispose (slot);
++
+ nautilus_window_slot_clear_forward_list (slot);
+ nautilus_window_slot_clear_back_list (slot);
+
 @@ -2491,6 +2614,7 @@
   oclass->constructed = nautilus_window_slot_constructed;
   oclass->set_property = nautilus_window_slot_set_property;

Revision history for this message
Robert Ancell (robert-ancell) wrote :

Yes, a separate merge request is best - is there a bug associated with this fix?

Revision history for this message
Daniel Wyatt (daniel-wyatt) wrote :

Created a merge request:
https://code.launchpad.net/~daniel-wyatt/nautilus/ubuntu/+merge/203450

No, I never created a bug report for this.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-01-10 16:46:15 +0000
3+++ debian/changelog 2014-01-10 22:45:26 +0000
4@@ -1,3 +1,10 @@
5+nautilus (1:3.8.2-0ubuntu5) UNRELEASED; urgency=medium
6+
7+ * debian/patches/interactive_search.patch:
8+ - Restore interactive search as an option (lp: #1164016)
9+
10+ -- Daniel Wyatt <Daniel.Wyatt@gmail.com> Fri, 10 Jan 2014 17:45:16 +0100
11+
12 nautilus (1:3.8.2-0ubuntu5) trusty; urgency=medium
13
14 * debian/patches/git_rename_display.patch:
15
16=== added file 'debian/patches/interactive_search.patch'
17--- debian/patches/interactive_search.patch 1970-01-01 00:00:00 +0000
18+++ debian/patches/interactive_search.patch 2014-01-10 22:45:26 +0000
19@@ -0,0 +1,1019 @@
20+=== modified file 'libnautilus-private/nautilus-global-preferences.h'
21+--- libnautilus-private/nautilus-global-preferences.h 2013-06-21 17:10:06 +0000
22++++ libnautilus-private/nautilus-global-preferences.h 2013-12-10 06:59:46 +0000
23+@@ -160,6 +160,7 @@
24+ /* Recent files */
25+ #define NAUTILUS_PREFERENCES_RECENT_FILES_ENABLED "remember-recent-files"
26+
27++#define NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH "enable-interactive-search"
28+
29+ void nautilus_global_preferences_init (void);
30+ char *nautilus_global_preferences_get_default_folder_viewer_preference_as_iid (void);
31+
32+=== modified file 'libnautilus-private/org.gnome.nautilus.gschema.xml.in'
33+--- libnautilus-private/org.gnome.nautilus.gschema.xml.in 2013-06-21 17:10:06 +0000
34++++ libnautilus-private/org.gnome.nautilus.gschema.xml.in 2013-12-10 06:59:46 +0000
35+@@ -164,6 +164,11 @@
36+ <_summary>Bulk rename utility</_summary>
37+ <_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>
38+ </key>
39++ <key name="enable-interactive-search" type="b">
40++ <default>false</default>
41++ <_summary>Enable interactive (type-ahead) search</_summary>
42++ <_description>If set to true, enables interactive search, similar to Nautilus 3.4.</_description>
43++ </key>
44+ </schema>
45+
46+ <schema id="org.gnome.nautilus.icon-view" path="/org/gnome/nautilus/icon-view/" gettext-domain="nautilus">
47+
48+=== modified file 'src/nautilus-list-view.c'
49+--- src/nautilus-list-view.c 2013-06-21 17:10:06 +0000
50++++ src/nautilus-list-view.c 2013-12-23 06:12:15 +0000
51+@@ -2364,6 +2364,7 @@
52+ GList *node;
53+ GList *iters, *l;
54+ NautilusFile *file;
55++ GtkTreePath *path = NULL;
56+
57+ list_view = NAUTILUS_LIST_VIEW (view);
58+ tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
59+@@ -2378,10 +2379,19 @@
60+ for (l = iters; l != NULL; l = l->next) {
61+ gtk_tree_selection_select_iter (tree_selection,
62+ (GtkTreeIter *)l->data);
63++ if (!path)
64++ path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), (GtkTreeIter *)l->data);
65+ }
66+ g_list_free_full (iters, g_free);
67+ }
68+-
69++ if (path) {
70++ gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
71++ path,
72++ list_view->details->file_name_column,
73++ GTK_CELL_RENDERER (list_view->details->file_name_cell),
74++ TRUE);
75++ gtk_tree_path_free (path);
76++ }
77+ g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
78+ nautilus_view_notify_selection_changed (view);
79+ }
80+
81+=== modified file 'src/nautilus-window-slot.c'
82+--- src/nautilus-window-slot.c 2013-06-21 17:10:06 +0000
83++++ src/nautilus-window-slot.c 2013-12-20 23:51:03 +0000
84+@@ -128,6 +128,17 @@
85+ gboolean tried_mount;
86+ NautilusWindowGoToCallback open_callback;
87+ gpointer open_callback_user_data;
88++
89++ /* Interactive search */
90++ gboolean isearch_enable;
91++ gboolean isearch_imcontext_changed;
92++ gboolean isearch_disable_hide;
93++ NautilusFile *isearch_selected_file;
94++ GtkWidget *isearch_window;
95++ GtkWidget *isearch_entry;
96++ gulong isearch_entry_changed_id;
97++ guint isearch_timeout_id;
98++ gulong isearch_configure_event_id;
99+ };
100+
101+ static guint signals[LAST_SIGNAL] = { 0 };
102+@@ -138,6 +149,16 @@
103+ static void nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *slot);
104+ static void nautilus_window_slot_emit_location_change (NautilusWindowSlot *slot, GFile *from, GFile *to);
105+
106++/* Interactive search */
107++static void isearch_ensure (NautilusWindowSlot *slot);
108++static gboolean isearch_start (NautilusWindowSlot *slot, GdkDevice *device);
109++static void isearch_enable_changed (gpointer callback_data);
110++static void isearch_dispose (NautilusWindowSlot *slot);
111++static void isearch_hide (NautilusWindowSlot *slot,
112++ GdkDevice *device);
113++
114++#define ISEARCH_TIMEOUT 5000
115++
116+ static void
117+ nautilus_window_slot_sync_search_widgets (NautilusWindowSlot *slot)
118+ {
119+@@ -442,17 +463,86 @@
120+
121+ retval = FALSE;
122+ window = nautilus_window_slot_get_window (slot);
123+- if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
124+- retval = nautilus_query_editor_handle_event (slot->details->query_editor, event);
125+- }
126+-
127+- if (retval) {
128+- nautilus_window_slot_set_search_visible (slot, TRUE);
129+- }
130+-
131++
132++ if (slot->details->isearch_enable) {
133++ GdkEvent *new_event;
134++ char *old_text;
135++ const char *new_text;
136++ gboolean retval;
137++ GdkScreen *screen;
138++ gboolean text_modified;
139++ gulong popup_menu_id;
140++
141++ isearch_ensure (slot);
142++
143++ /* Make a copy of the current text */
144++ old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (slot->details->isearch_entry)));
145++ new_event = gdk_event_copy ((GdkEvent *) event);
146++ g_object_unref (((GdkEventKey *) new_event)->window);
147++ ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (slot->details->isearch_window));
148++ gtk_widget_realize (slot->details->isearch_window);
149++
150++ popup_menu_id = g_signal_connect (slot->details->isearch_entry,
151++ "popup-menu", G_CALLBACK (gtk_true),
152++ NULL);
153++
154++ /* Move the entry off screen */
155++ screen = gtk_widget_get_screen (GTK_WIDGET (slot));
156++ gtk_window_move (GTK_WINDOW (slot->details->isearch_window),
157++ gdk_screen_get_width (screen) + 1,
158++ gdk_screen_get_height (screen) + 1);
159++ gtk_widget_show (slot->details->isearch_window);
160++
161++ /* Send the event to the window. If the preedit_changed signal is emitted
162++ * during this event, we will set priv->imcontext_changed */
163++ slot->details->isearch_imcontext_changed = FALSE;
164++ retval = gtk_widget_event (slot->details->isearch_window, new_event);
165++ gdk_event_free (new_event);
166++ gtk_widget_hide (slot->details->isearch_window);
167++
168++ g_signal_handler_disconnect (slot->details->isearch_entry,
169++ popup_menu_id);
170++
171++ /* We check to make sure that the entry tried to handle the text, and that
172++ * the text has changed.
173++ */
174++ new_text = gtk_entry_get_text (GTK_ENTRY (slot->details->isearch_entry));
175++ text_modified = strcmp (old_text, new_text) != 0;
176++ g_free (old_text);
177++ if (slot->details->isearch_imcontext_changed ||
178++ (retval && text_modified))
179++ {
180++ if (isearch_start (slot,
181++ gdk_event_get_device ((GdkEvent *) event))) {
182++ gtk_widget_grab_focus (GTK_WIDGET (slot));
183++ return TRUE;
184++ }
185++ else {
186++ gtk_entry_set_text (GTK_ENTRY (slot->details->isearch_entry), "");
187++ return FALSE;
188++ }
189++ }
190++ } else {
191++ if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
192++ retval = nautilus_query_editor_handle_event (slot->details->query_editor, event);
193++ }
194++
195++ if (retval) {
196++ nautilus_window_slot_set_search_visible (slot, TRUE);
197++ }
198++ }
199+ return retval;
200+ }
201+
202++static gboolean
203++configure_event_cb (GtkWidget *widget,
204++ GdkEventConfigure *event,
205++ NautilusWindowSlot *slot)
206++{
207++ isearch_hide (slot, NULL);
208++ return FALSE;
209++}
210++
211+ static void
212+ real_active (NautilusWindowSlot *slot)
213+ {
214+@@ -477,6 +567,13 @@
215+ nautilus_window_slot_sync_view_as_menus (slot);
216+ nautilus_window_load_extension_menus (window);
217+ }
218++ if (slot->details->isearch_configure_event_id == 0) {
219++ slot->details->isearch_configure_event_id =
220++ g_signal_connect (GTK_WIDGET (slot->details->window),
221++ "configure-event",
222++ G_CALLBACK (configure_event_cb),
223++ slot);
224++ }
225+ }
226+
227+ static void
228+@@ -486,6 +583,12 @@
229+
230+ window = nautilus_window_slot_get_window (slot);
231+ g_assert (slot == nautilus_window_get_active_slot (window));
232++ isearch_hide (slot, NULL);
233++ if (slot->details->isearch_configure_event_id != 0) {
234++ g_signal_handler_disconnect (GTK_WIDGET (slot->details->window),
235++ slot->details->isearch_configure_event_id);
236++ slot->details->isearch_configure_event_id = 0;
237++ }
238+ }
239+
240+ static void
241+@@ -612,6 +715,26 @@
242+ {
243+ slot->details = G_TYPE_INSTANCE_GET_PRIVATE
244+ (slot, NAUTILUS_TYPE_WINDOW_SLOT, NautilusWindowSlotDetails);
245++
246++ slot->details->isearch_enable =
247++ g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH);
248++
249++ g_signal_connect_swapped (nautilus_preferences,
250++ "changed::" NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH,
251++ G_CALLBACK(isearch_enable_changed), slot);
252++}
253++
254++static void
255++nautilus_window_slot_finalize (GObject *object)
256++{
257++ NautilusWindowSlot *slot;
258++
259++ slot = NAUTILUS_WINDOW_SLOT (object);
260++
261++ g_signal_handlers_disconnect_by_func (nautilus_preferences,
262++ isearch_enable_changed, slot);
263++
264++ G_OBJECT_CLASS (nautilus_window_slot_parent_class)->finalize (object);
265+ }
266+
267+ static void
268+@@ -2491,6 +2614,7 @@
269+ oclass->constructed = nautilus_window_slot_constructed;
270+ oclass->set_property = nautilus_window_slot_set_property;
271+ oclass->get_property = nautilus_window_slot_get_property;
272++ oclass->finalize = nautilus_window_slot_finalize;
273+
274+ signals[ACTIVE] =
275+ g_signal_new ("active",
276+@@ -2847,3 +2971,761 @@
277+ "window", window,
278+ NULL);
279+ }
280++
281++/* Interactive search */
282++
283++static void
284++isearch_ensure (NautilusWindowSlot *slot);
285++static gboolean
286++isearch_timeout (gpointer user_data);
287++static void
288++isearch_timeout_destroy (gpointer user_data);
289++static void
290++isearch_timeout_restart (NautilusWindowSlot *slot);
291++static gboolean
292++isearch_window_delete_event (GtkWidget *widget,
293++ GdkEventAny *event,
294++ NautilusWindowSlot *slot);
295++static gboolean
296++isearch_window_button_press_event (GtkWidget *widget,
297++ GdkEventButton *event,
298++ NautilusWindowSlot *slot);
299++static gboolean
300++isearch_window_scroll_event (GtkWidget *widget,
301++ GdkEventScroll *event,
302++ NautilusWindowSlot *slot);
303++static void
304++isearch_activate_items_alternate (NautilusWindowSlot *slot);
305++static gboolean
306++isearch_window_key_press_event (GtkWidget *widget,
307++ GdkEventKey *event,
308++ NautilusWindowSlot *slot);
309++static void
310++isearch_disable_hide (GtkEntry *entry,
311++ GtkMenu *menu,
312++ gpointer data);
313++static void
314++isearch_preedit_changed (GtkEntry *entry,
315++ gchar *preedit,
316++ NautilusWindowSlot *slot);
317++static void
318++isearch_activate_event (GtkEntry *entry,
319++ NautilusWindowSlot *slot);
320++static gboolean
321++isearch_enable_hide_real (gpointer data);
322++static void
323++isearch_enable_hide (GtkWidget *widget,
324++ gpointer data);
325++static void
326++send_focus_change (GtkWidget *widget,
327++ GdkDevice *device,
328++ gboolean in);
329++static void
330++isearch_hide (NautilusWindowSlot *slot,
331++ GdkDevice *device);
332++static void
333++isearch_entry_changed (GtkWidget *entry,
334++ NautilusWindowSlot *slot);
335++static gboolean
336++isearch_start (NautilusWindowSlot *slot, GdkDevice *device);
337++static void
338++isearch_position (NautilusWindowSlot *slot);
339++static gboolean
340++isearch_compare_filename (const gchar *f1, const gchar *f2, guint length);
341++static int
342++compare_files (gconstpointer a, gconstpointer b, gpointer callback_data);
343++static GList *
344++isearch_get_sorted_files (NautilusWindowSlot *slot);
345++static NautilusFile *
346++isearch_find (NautilusWindowSlot *slot, const gchar *text);
347++static NautilusFile *
348++isearch_find_next (NautilusWindowSlot *slot, const gchar *text);
349++static NautilusFile *
350++isearch_find_prev (NautilusWindowSlot *slot, const gchar *text);
351++static gboolean
352++isearch_move_next (NautilusWindowSlot *slot);
353++static gboolean
354++isearch_move_prev (NautilusWindowSlot *slot);
355++static void
356++isearch_set_selection (NautilusWindowSlot *slot, NautilusFile *file);
357++static void
358++isearch_enable_changed (gpointer callback_data);
359++static void
360++isearch_dispose (NautilusWindowSlot *slot);
361++
362++static void
363++isearch_ensure (NautilusWindowSlot *slot)
364++{
365++ GtkWidget *frame, *vbox, *toplevel;
366++ GdkScreen *screen;
367++
368++ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (slot));
369++ screen = gtk_widget_get_screen (GTK_WIDGET (slot));
370++
371++ if (slot->details->isearch_window != NULL)
372++ {
373++ if (gtk_window_has_group (GTK_WINDOW (toplevel)))
374++ gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
375++ GTK_WINDOW (slot->details->isearch_window));
376++ else if (gtk_window_has_group (GTK_WINDOW (slot->details->isearch_window)))
377++ gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (slot->details->isearch_window)),
378++ GTK_WINDOW (slot->details->isearch_window));
379++
380++ gtk_window_set_screen (GTK_WINDOW (slot->details->isearch_window), screen);
381++ return;
382++ }
383++ slot->details->isearch_window = gtk_window_new (GTK_WINDOW_POPUP);
384++ gtk_window_set_screen (GTK_WINDOW (slot->details->isearch_window), screen);
385++
386++ if (gtk_window_has_group (GTK_WINDOW (toplevel)))
387++ gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
388++ GTK_WINDOW (slot->details->isearch_window));
389++
390++ gtk_window_set_type_hint (GTK_WINDOW (slot->details->isearch_window),
391++ GDK_WINDOW_TYPE_HINT_UTILITY);
392++ gtk_window_set_modal (GTK_WINDOW (slot->details->isearch_window), TRUE);
393++ g_signal_connect (slot->details->isearch_window, "delete-event",
394++ G_CALLBACK (isearch_window_delete_event),
395++ slot);
396++ g_signal_connect (slot->details->isearch_window, "key-press-event",
397++ G_CALLBACK (isearch_window_key_press_event),
398++ slot);
399++ g_signal_connect (slot->details->isearch_window, "button-press-event",
400++ G_CALLBACK (isearch_window_button_press_event),
401++ slot);
402++ g_signal_connect (slot->details->isearch_window, "scroll-event",
403++ G_CALLBACK (isearch_window_scroll_event),
404++ slot);
405++
406++ frame = gtk_frame_new (NULL);
407++ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
408++ gtk_widget_show (frame);
409++ gtk_container_add (GTK_CONTAINER (slot->details->isearch_window), frame);
410++
411++ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
412++ gtk_widget_show (vbox);
413++ gtk_container_add (GTK_CONTAINER (frame), vbox);
414++ gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
415++
416++ /* add entry */
417++ slot->details->isearch_entry = gtk_entry_new ();
418++ gtk_widget_show (slot->details->isearch_entry);
419++ g_signal_connect (slot->details->isearch_entry, "populate-popup",
420++ G_CALLBACK (isearch_disable_hide),
421++ slot);
422++ g_signal_connect (slot->details->isearch_entry,
423++ "activate", G_CALLBACK (isearch_activate_event),
424++ slot);
425++
426++ g_signal_connect (G_OBJECT (slot->details->isearch_entry),
427++ "preedit-changed",
428++ G_CALLBACK (isearch_preedit_changed),
429++ slot);
430++ gtk_container_add (GTK_CONTAINER (vbox),
431++ slot->details->isearch_entry);
432++
433++ gtk_widget_realize (slot->details->isearch_entry);
434++}
435++
436++static gboolean
437++isearch_timeout (gpointer user_data)
438++{
439++ NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (user_data);
440++
441++ if (!g_source_is_destroyed (g_main_current_source ()))
442++ isearch_hide (slot, NULL);
443++
444++ return FALSE;
445++}
446++
447++static void
448++isearch_timeout_destroy (gpointer user_data)
449++{
450++ NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (user_data);
451++
452++ slot->details->isearch_timeout_id = 0;
453++}
454++
455++static void
456++isearch_timeout_restart (NautilusWindowSlot *slot)
457++{
458++ if (slot->details->isearch_timeout_id != 0) {
459++ g_source_remove (slot->details->isearch_timeout_id);
460++
461++ slot->details->isearch_timeout_id = gdk_threads_add_timeout_full (
462++ G_PRIORITY_LOW, ISEARCH_TIMEOUT,
463++ isearch_timeout,
464++ slot,
465++ isearch_timeout_destroy);
466++ }
467++}
468++
469++static gboolean
470++isearch_window_delete_event (GtkWidget *widget,
471++ GdkEventAny *event,
472++ NautilusWindowSlot *slot)
473++{
474++ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
475++
476++ isearch_hide (slot, NULL);
477++ return TRUE;
478++}
479++
480++static gboolean
481++isearch_window_button_press_event (GtkWidget *widget,
482++ GdkEventButton *event,
483++ NautilusWindowSlot *slot)
484++{
485++ GdkDevice *keyb_device;
486++
487++ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
488++
489++ keyb_device = gdk_device_get_associated_device (event->device);
490++ isearch_hide (slot, keyb_device);
491++
492++ /* A bit of hackery here */
493++ if (NAUTILUS_IS_CANVAS_VIEW (slot->details->content_view)) {
494++ NautilusCanvasContainer *cc = nautilus_canvas_view_get_canvas_container (NAUTILUS_CANVAS_VIEW (slot->details->content_view));
495++ gboolean retval;
496++
497++ if (event->window == gtk_layout_get_bin_window (GTK_LAYOUT (cc)))
498++ g_signal_emit_by_name (GTK_WIDGET (cc), "button-press-event", event, &retval);
499++
500++ return retval;
501++ } else if (NAUTILUS_IS_LIST_VIEW (slot->details->content_view)) {
502++ NautilusListView *lv = NAUTILUS_LIST_VIEW (slot->details->content_view);
503++ GtkTreeView *tv = nautilus_list_view_get_tree_view (NAUTILUS_LIST_VIEW (slot->details->content_view));
504++ gboolean retval;
505++
506++ if (event->window == gtk_tree_view_get_bin_window (tv))
507++ g_signal_emit_by_name (GTK_WIDGET (tv), "button-press-event", event, &retval);
508++
509++ return retval;
510++ }
511++ return TRUE;
512++}
513++
514++static gboolean
515++isearch_window_scroll_event (GtkWidget *widget,
516++ GdkEventScroll *event,
517++ NautilusWindowSlot *slot)
518++{
519++ gboolean retval = FALSE;
520++
521++ if (event->direction == GDK_SCROLL_UP) {
522++ isearch_move_prev (slot);
523++ retval = TRUE;
524++ }
525++ else if (event->direction == GDK_SCROLL_DOWN) {
526++ isearch_move_next (slot);
527++ retval = TRUE;
528++ }
529++ if (retval)
530++ isearch_timeout_restart (slot);
531++
532++ return retval;
533++}
534++
535++static void
536++isearch_activate_items_alternate (NautilusWindowSlot *slot)
537++{
538++ GList *file_list;
539++
540++ file_list = nautilus_view_get_selection (slot->details->content_view);
541++ nautilus_view_activate_files (NAUTILUS_VIEW (slot->details->content_view),
542++ file_list,
543++ NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB,
544++ TRUE);
545++ nautilus_file_list_free (file_list);
546++}
547++
548++static gboolean
549++isearch_window_key_press_event (GtkWidget *widget,
550++ GdkEventKey *event,
551++ NautilusWindowSlot *slot)
552++{
553++ GdkModifierType default_accel;
554++ gboolean retval = FALSE;
555++
556++ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
557++ g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot), FALSE);
558++
559++ /* close window and cancel the search */
560++ if (event->keyval == GDK_KEY_Escape ||
561++ event->keyval == GDK_KEY_Tab ||
562++ event->keyval == GDK_KEY_KP_Tab ||
563++ event->keyval == GDK_KEY_ISO_Left_Tab) {
564++
565++ isearch_hide (slot, gdk_event_get_device ((GdkEvent *) event));
566++ return TRUE;
567++ }
568++
569++ default_accel = gtk_widget_get_modifier_mask (widget,
570++ GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
571++
572++ /* select previous matching iter */
573++ if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) {
574++ if (!isearch_move_prev (slot))
575++ gtk_widget_error_bell (widget);
576++
577++ retval = TRUE;
578++ }
579++ if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
580++ && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) {
581++ if (!isearch_move_prev (slot))
582++ gtk_widget_error_bell (widget);
583++
584++ retval = TRUE;
585++ }
586++ /* select next matching iter */
587++ if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) {
588++ if (!isearch_move_next (slot))
589++ gtk_widget_error_bell (widget);
590++
591++ retval = TRUE;
592++ }
593++ if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
594++ && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) {
595++ if (!isearch_move_next (slot))
596++ gtk_widget_error_bell (widget);
597++
598++ retval = TRUE;
599++ }
600++
601++ /* Alternate activation (Shift+Enter).
602++ * Regular activation (Enter) is handled by the entry activate signal.
603++ */
604++ if ((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) &&
605++ (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
606++ isearch_activate_items_alternate (slot);
607++ isearch_hide (slot, gdk_event_get_device ((GdkEvent*)event));
608++ retval = TRUE;
609++ }
610++ isearch_timeout_restart (slot);
611++ return retval;
612++}
613++
614++static void
615++isearch_disable_hide (GtkEntry *entry,
616++ GtkMenu *menu,
617++ gpointer data)
618++{
619++ NautilusWindowSlot *slot = (NautilusWindowSlot *)data;
620++
621++ slot->details->isearch_disable_hide = 1;
622++ g_signal_connect (menu, "hide",
623++ G_CALLBACK (isearch_enable_hide), data);
624++}
625++
626++static void
627++isearch_preedit_changed (GtkEntry *entry,
628++ gchar *preedit,
629++ NautilusWindowSlot *slot)
630++{
631++ slot->details->isearch_imcontext_changed = 1;
632++ isearch_timeout_restart (slot);
633++}
634++
635++static void
636++isearch_activate_event (GtkEntry *entry,
637++ NautilusWindowSlot *slot)
638++{
639++ GtkTreePath *path;
640++
641++ isearch_hide (slot, gtk_get_current_event_device ());
642++ nautilus_view_activate_selection (slot->details->content_view);
643++}
644++
645++static gboolean
646++isearch_enable_hide_real (gpointer data)
647++{
648++ NautilusWindowSlot *slot = (NautilusWindowSlot *)data;
649++ slot->details->isearch_disable_hide = 0;
650++ return FALSE;
651++}
652++
653++static void
654++isearch_enable_hide (GtkWidget *widget,
655++ gpointer data)
656++{
657++ gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, isearch_enable_hide_real, g_object_ref (data), g_object_unref);
658++}
659++
660++static void
661++send_focus_change (GtkWidget *widget,
662++ GdkDevice *device,
663++ gboolean in)
664++{
665++ GdkDeviceManager *device_manager;
666++ GList *devices, *d;
667++
668++ device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
669++ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
670++ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
671++ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
672++
673++ for (d = devices; d; d = d->next)
674++ {
675++ GdkDevice *dev = d->data;
676++ GdkEvent *fevent;
677++ GdkWindow *window;
678++
679++ if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
680++ continue;
681++
682++ window = gtk_widget_get_window (widget);
683++
684++ /* Skip non-master keyboards that haven't
685++ * selected for events from this window
686++ */
687++ if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
688++ !gdk_window_get_device_events (window, dev))
689++ continue;
690++
691++ fevent = gdk_event_new (GDK_FOCUS_CHANGE);
692++
693++ fevent->focus_change.type = GDK_FOCUS_CHANGE;
694++ fevent->focus_change.window = g_object_ref (window);
695++ fevent->focus_change.in = in;
696++ gdk_event_set_device (fevent, device);
697++
698++ gtk_widget_send_focus_change (widget, fevent);
699++
700++ gdk_event_free (fevent);
701++ }
702++
703++ g_list_free (devices);
704++}
705++
706++static void
707++isearch_hide (NautilusWindowSlot *slot,
708++ GdkDevice *device)
709++{
710++ if (slot->details->isearch_disable_hide)
711++ return;
712++
713++ if (!slot->details->isearch_enable)
714++ return;
715++
716++ if (slot->details->isearch_entry_changed_id)
717++ {
718++ g_signal_handler_disconnect (slot->details->isearch_entry,
719++ slot->details->isearch_entry_changed_id);
720++ slot->details->isearch_entry_changed_id = 0;
721++ }
722++ if (slot->details->isearch_timeout_id)
723++ {
724++ g_source_remove (slot->details->isearch_timeout_id);
725++ slot->details->isearch_timeout_id = 0;
726++ }
727++ if (slot->details->isearch_window != NULL
728++ && gtk_widget_get_visible (slot->details->isearch_window))
729++ {
730++ /* send focus-in event */
731++ send_focus_change (GTK_WIDGET (slot->details->isearch_entry), device, FALSE);
732++ gtk_widget_hide (slot->details->isearch_window);
733++ gtk_entry_set_text (GTK_ENTRY (slot->details->isearch_entry), "");
734++ send_focus_change (GTK_WIDGET (slot), device, TRUE);
735++ }
736++}
737++
738++static void
739++isearch_entry_changed (GtkWidget *entry,
740++ NautilusWindowSlot *slot)
741++{
742++ gint ret;
743++ const gchar *text;
744++
745++ g_return_if_fail (GTK_IS_ENTRY (entry));
746++ g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot));
747++
748++ text = gtk_entry_get_text (GTK_ENTRY (entry));
749++
750++ /* unselect all */
751++ nautilus_view_set_selection (slot->details->content_view, NULL);
752++
753++ isearch_timeout_restart (slot);
754++
755++ if (*text == '\0')
756++ return;
757++
758++ isearch_set_selection (slot, isearch_find (slot, text));
759++}
760++
761++static gboolean
762++isearch_start (NautilusWindowSlot *slot, GdkDevice *device)
763++{
764++ GTypeClass *klass;
765++ GList *list;
766++ gboolean found_focus = FALSE;
767++
768++ if (!slot->details->isearch_enable)
769++ return FALSE;
770++
771++ if (slot->details->isearch_window != NULL &&
772++ gtk_widget_get_visible (slot->details->isearch_window))
773++ return TRUE;
774++
775++ if (nautilus_view_get_loading (slot->details->content_view))
776++ return FALSE;
777++
778++ isearch_ensure (slot);
779++
780++ /* done, show it */
781++ isearch_position (slot);
782++ gtk_widget_show (slot->details->isearch_window);
783++ if (slot->details->isearch_entry_changed_id == 0)
784++ {
785++ slot->details->isearch_entry_changed_id =
786++ g_signal_connect (slot->details->isearch_entry, "changed",
787++ G_CALLBACK (isearch_entry_changed),
788++ slot);
789++ }
790++ slot->details->isearch_timeout_id = gdk_threads_add_timeout_full (
791++ G_PRIORITY_LOW,
792++ ISEARCH_TIMEOUT,
793++ isearch_timeout,
794++ slot,
795++ isearch_timeout_destroy);
796++
797++ /* Grab focus without selecting all the text. */
798++ klass = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (slot->details->isearch_entry));
799++ (*GTK_WIDGET_CLASS (klass)->grab_focus) (slot->details->isearch_entry);
800++
801++ /* send focus-in event */
802++ send_focus_change (slot->details->isearch_entry, device, TRUE);
803++
804++ /* search first matching iter */
805++ isearch_entry_changed (slot->details->isearch_entry, slot);
806++ return TRUE;
807++}
808++
809++static void
810++isearch_position (NautilusWindowSlot *slot)
811++{
812++ gint x, y;
813++ gint window_x, window_y;
814++ gint window_width, window_height;
815++ GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (slot));
816++ GdkScreen *screen = gdk_window_get_screen (window);
817++ GtkRequisition requisition;
818++ gint monitor_num;
819++ GdkRectangle monitor;
820++
821++ monitor_num = gdk_screen_get_monitor_at_window (screen, window);
822++ gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
823++
824++ gtk_widget_realize (slot->details->isearch_window);
825++
826++ gdk_window_get_origin (window, &window_x, &window_y);
827++ window_width = gdk_window_get_width (window);
828++ window_height = gdk_window_get_height (window);
829++ gtk_widget_get_preferred_size (slot->details->isearch_window, &requisition, NULL);
830++
831++ if (window_x + window_width > gdk_screen_get_width (screen))
832++ x = gdk_screen_get_width (screen) - requisition.width;
833++ else if (window_x + window_width - requisition.width < 0)
834++ x = 0;
835++ else
836++ x = window_x + window_width - requisition.width;
837++
838++ if (window_y + window_height + requisition.height > gdk_screen_get_height (screen))
839++ y = gdk_screen_get_height (screen) - requisition.height;
840++ else if (window_y + window_height < 0) /* isn't really possible ... */
841++ y = 0;
842++ else
843++ y = window_y + window_height;
844++
845++ gtk_window_move (GTK_WINDOW (slot->details->isearch_window), x, y);
846++}
847++
848++static gboolean
849++isearch_compare_filename (const gchar *f1, const gchar *f2, guint length)
850++{
851++ gchar *normalized_f1;
852++ gchar *normalized_f2;
853++ gchar *case_normalized_f1;
854++ gchar *case_normalized_f2;
855++ gboolean retval = FALSE;
856++
857++ normalized_f1 = g_utf8_normalize (f1, -1, G_NORMALIZE_ALL);
858++ normalized_f2 = g_utf8_normalize (f2, -1, G_NORMALIZE_ALL);
859++
860++ if (G_LIKELY (normalized_f1 != NULL && normalized_f2 != NULL)) {
861++ case_normalized_f1 = g_utf8_casefold (normalized_f1, -1);
862++ case_normalized_f2 = g_utf8_casefold (normalized_f2, -1);
863++
864++ retval = (strncmp (case_normalized_f1, case_normalized_f2, length) == 0);
865++ }
866++ g_free (normalized_f1);
867++ g_free (normalized_f2);
868++ g_free (case_normalized_f1);
869++ g_free (case_normalized_f2);
870++ return retval;
871++}
872++
873++static int
874++compare_files (gconstpointer a, gconstpointer b, gpointer callback_data)
875++{
876++ NautilusView *view = NAUTILUS_VIEW (callback_data);
877++ NautilusFile *f1 = NAUTILUS_FILE (a);
878++ NautilusFile *f2 = NAUTILUS_FILE (b);
879++
880++ return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, f1, f2);
881++}
882++
883++static GList *
884++isearch_get_sorted_files (NautilusWindowSlot *slot)
885++{
886++ NautilusView *view = slot->details->content_view;
887++ NautilusDirectory *dir = nautilus_view_get_model (view);
888++ GList *list = nautilus_directory_get_file_list (dir);
889++ GList *sorted_list;
890++
891++ sorted_list = g_list_sort_with_data (list, compare_files, view);
892++ return sorted_list;
893++}
894++
895++static NautilusFile *
896++isearch_find (NautilusWindowSlot *slot, const gchar *text)
897++{
898++ GList *files = isearch_get_sorted_files (slot);
899++ GList *l;
900++ NautilusFile *found = NULL;
901++
902++ for (l = files; l; l = g_list_next (l)) {
903++ NautilusFile *file = NAUTILUS_FILE (l->data);
904++ gchar *filename = nautilus_file_get_display_name (file);
905++
906++ if (isearch_compare_filename (filename, text, strlen (text)))
907++ found = file;
908++
909++ g_free (filename);
910++ if (found)
911++ break;
912++ }
913++ return found;
914++}
915++
916++static NautilusFile *
917++isearch_find_next (NautilusWindowSlot *slot, const gchar *text)
918++{
919++ GList *files = isearch_get_sorted_files (slot);
920++ NautilusFile *found = NULL;
921++ GList *current;
922++ GList *l;
923++
924++ current = g_list_find (files, slot->details->isearch_selected_file);
925++ for (l = g_list_next (current); l; l = g_list_next (l)) {
926++ NautilusFile *file = NAUTILUS_FILE (l->data);
927++ gchar *display_name = nautilus_file_get_display_name (file);
928++
929++ if (isearch_compare_filename (display_name, text, strlen (text)))
930++ found = file;
931++
932++ g_free (display_name);
933++ if (found)
934++ break;
935++ }
936++ return found;
937++}
938++
939++static NautilusFile *
940++isearch_find_prev (NautilusWindowSlot *slot, const gchar *text)
941++{
942++ GList *files = isearch_get_sorted_files (slot);
943++ NautilusFile *found = NULL;
944++ GList *current;
945++ GList *l;
946++
947++ current = g_list_find (files, slot->details->isearch_selected_file);
948++ for (l = g_list_previous (current); l; l = g_list_previous (l)) {
949++ NautilusFile *file = NAUTILUS_FILE (l->data);
950++ gchar *display_name = nautilus_file_get_display_name (file);
951++
952++ if (isearch_compare_filename (display_name, text, strlen (text)))
953++ found = file;
954++
955++ g_free (display_name);
956++ if (found)
957++ break;
958++ }
959++ return found;
960++}
961++
962++static gboolean
963++isearch_move_next (NautilusWindowSlot *slot)
964++{
965++ const gchar *text;
966++ NautilusFile *iter;
967++
968++ text = gtk_entry_get_text (GTK_ENTRY (slot->details->isearch_entry));
969++ iter = isearch_find_next (slot, text);
970++ if (iter)
971++ isearch_set_selection (slot, iter);
972++
973++ return iter != NULL;
974++}
975++
976++static gboolean
977++isearch_move_prev (NautilusWindowSlot *slot)
978++{
979++ const gchar *text;
980++ NautilusFile *iter;
981++
982++ text = gtk_entry_get_text (GTK_ENTRY (slot->details->isearch_entry));
983++ iter = isearch_find_prev (slot, text);
984++ if (iter)
985++ isearch_set_selection (slot, iter);
986++
987++ return iter != NULL;
988++}
989++
990++static void
991++isearch_set_selection (NautilusWindowSlot *slot, NautilusFile *file)
992++{
993++ GList *list = g_list_append (list, file);
994++
995++ slot->details->isearch_selected_file = file;
996++ nautilus_view_set_selection (slot->details->content_view, list);
997++ g_list_free (list);
998++}
999++
1000++static void
1001++isearch_enable_changed (gpointer callback_data)
1002++{
1003++ NautilusWindowSlot *slot;
1004++ gboolean enable;
1005++
1006++ slot = NAUTILUS_WINDOW_SLOT (callback_data);
1007++
1008++ enable = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ENABLE_INTERACTIVE_SEARCH);
1009++
1010++ if (enable != slot->details->isearch_enable) {
1011++ if (!enable)
1012++ isearch_dispose (slot);
1013++
1014++ slot->details->isearch_enable = enable;
1015++ }
1016++}
1017++
1018++static void
1019++isearch_dispose (NautilusWindowSlot *slot)
1020++{
1021++ if (!slot->details->isearch_enable)
1022++ return;
1023++
1024++ if (slot->details->isearch_entry_changed_id != 0) {
1025++ g_signal_handler_disconnect (G_OBJECT (slot->details->isearch_entry), slot->details->isearch_entry_changed_id);
1026++ slot->details->isearch_entry_changed_id = 0;
1027++ }
1028++ if (slot->details->isearch_timeout_id != 0) {
1029++ g_source_remove (slot->details->isearch_timeout_id);
1030++ slot->details->isearch_timeout_id = 0;
1031++ }
1032++ if (slot->details->isearch_window != NULL) {
1033++ gtk_widget_destroy (slot->details->isearch_window);
1034++ slot->details->isearch_window = NULL;
1035++ slot->details->isearch_entry = NULL;
1036++ }
1037++}
1038+
1039
1040=== modified file 'debian/patches/series'
1041--- debian/patches/series 2014-01-10 16:45:46 +0000
1042+++ debian/patches/series 2014-01-10 22:45:26 +0000
1043@@ -24,3 +24,4 @@
1044 git_correct_context_menu.patch
1045 git_rtl_icons.patch
1046 git_rename_display.patch
1047+interactive_search.patch

Subscribers

People subscribed via source and target branches

to all changes: