2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* minibuffer.c - for handling the path entry box at the bottom */
31 #include <sys/types.h>
35 #include <gdk/gdkkeysyms.h>
41 #include "gui_support.h"
43 #include "minibuffer.h"
50 #include "view_iface.h"
52 static GList
*shell_history
= NULL
;
54 /* Static prototypes */
55 static gint
key_press_event(GtkWidget
*widget
,
57 FilerWindow
*filer_window
);
58 static void changed(GtkEditable
*mini
, FilerWindow
*filer_window
);
59 static gboolean
find_next_match(FilerWindow
*filer_window
,
62 static gboolean
find_exact_match(FilerWindow
*filer_window
,
63 const gchar
*pattern
);
64 static gboolean
matches(ViewIter
*iter
, const char *pattern
);
65 static void search_in_dir(FilerWindow
*filer_window
, int dir
);
66 static const gchar
*mini_contents(FilerWindow
*filer_window
);
67 static void show_help(FilerWindow
*filer_window
);
68 static gboolean
grab_focus(GtkWidget
*minibuffer
);
69 static gboolean
select_if_glob(ViewIter
*iter
, gpointer data
);
71 /****************************************************************
72 * EXTERNAL INTERFACE *
73 ****************************************************************/
75 static Option o_filer_beep_fail
, o_filer_beep_multi
;
77 void minibuffer_init(void)
79 option_add_int(&o_filer_beep_fail
, "filer_beep_fail", 1);
80 option_add_int(&o_filer_beep_multi
, "filer_beep_multi", 1);
83 /* Creates the minibuffer widgets, setting the appropriate fields
86 void create_minibuffer(FilerWindow
*filer_window
)
88 GtkWidget
*hbox
, *label
, *mini
;
90 hbox
= gtk_hbox_new(FALSE
, 0);
92 gtk_box_pack_start(GTK_BOX(hbox
),
93 new_help_button((HelpFunc
) show_help
, filer_window
),
96 label
= gtk_label_new("");
97 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 2);
99 mini
= gtk_entry_new();
100 gtk_box_pack_start(GTK_BOX(hbox
), mini
, TRUE
, TRUE
, 0);
101 gtk_widget_set_name(mini
, "fixed-style");
102 g_signal_connect(mini
, "key_press_event",
103 G_CALLBACK(key_press_event
), filer_window
);
104 g_signal_connect(mini
, "changed", G_CALLBACK(changed
), filer_window
);
106 /* Grabbing focus musn't select the text... */
107 g_signal_connect_swapped(mini
, "grab-focus",
108 G_CALLBACK(grab_focus
), mini
);
110 filer_window
->minibuffer
= mini
;
111 filer_window
->minibuffer_label
= label
;
112 filer_window
->minibuffer_area
= hbox
;
115 void minibuffer_show(FilerWindow
*filer_window
, MiniType mini_type
)
121 g_return_if_fail(filer_window
!= NULL
);
122 g_return_if_fail(filer_window
->minibuffer
!= NULL
);
124 mini
= GTK_ENTRY(filer_window
->minibuffer
);
125 entry_set_error(filer_window
->minibuffer
, FALSE
);
127 filer_window
->mini_type
= MINI_NONE
;
128 gtk_label_set_text(GTK_LABEL(filer_window
->minibuffer_label
),
129 mini_type
== MINI_PATH
? _("Goto:") :
130 mini_type
== MINI_SHELL
? _("Shell:") :
131 mini_type
== MINI_SELECT_IF
? _("Select If:") :
132 mini_type
== MINI_SELECT_BY_NAME
? _("Select Named:") :
133 mini_type
== MINI_FILTER
? _("Pattern:") :
139 view_show_cursor(filer_window
->view
);
140 view_get_cursor(filer_window
->view
, &cursor
);
141 view_set_base(filer_window
->view
, &cursor
);
143 gtk_entry_set_text(mini
,
144 make_path(filer_window
->sym_path
, ""));
145 if (filer_window
->temp_show_hidden
)
147 filer_window
->temp_show_hidden
= FALSE
;
148 display_update_hidden(filer_window
);
152 gtk_entry_set_text(mini
, "");
153 filer_window
->mini_cursor_base
= -1; /* History */
155 case MINI_SELECT_BY_NAME
:
156 gtk_entry_set_text(mini
, "*.");
157 filer_window
->mini_cursor_base
= -1; /* History */
158 view_select_if(filer_window
->view
, select_if_glob
, "*.");
161 if(filer_window
->filter
!=FILER_SHOW_GLOB
||
162 !filer_window
->filter_string
)
163 gtk_entry_set_text(mini
, "*");
165 gtk_entry_set_text(mini
,
166 filer_window
->filter_string
);
171 view_get_cursor(filer_window
->view
, &cursor
);
172 item
= cursor
.peek(&cursor
);
174 if (view_count_selected(filer_window
->view
) > 0)
175 gtk_entry_set_text(mini
, " \"$@\"");
181 escaped
= shell_escape(item
->leafname
);
182 tmp
= g_strconcat(" ", escaped
, NULL
);
184 gtk_entry_set_text(mini
, tmp
);
188 gtk_entry_set_text(mini
, "");
189 filer_window
->mini_cursor_base
= -1; /* History */
193 g_warning("Bad minibuffer type\n");
197 filer_window
->mini_type
= mini_type
;
199 gtk_editable_set_position(GTK_EDITABLE(mini
), pos
);
201 gtk_widget_show_all(filer_window
->minibuffer_area
);
203 gtk_widget_grab_focus(filer_window
->minibuffer
);
206 void minibuffer_hide(FilerWindow
*filer_window
)
208 filer_window
->mini_type
= MINI_NONE
;
210 gtk_widget_hide(filer_window
->minibuffer_area
);
212 gtk_widget_child_focus(filer_window
->window
, GTK_DIR_TAB_FORWARD
);
214 if (filer_window
->temp_show_hidden
)
219 view_get_cursor(filer_window
->view
, &iter
);
220 item
= iter
.peek(&iter
);
222 if (item
== NULL
|| item
->leafname
[0] != '.')
223 display_update_hidden(filer_window
);
224 filer_window
->temp_show_hidden
= FALSE
;
228 /* Insert this leafname at the cursor (replacing the selection, if any).
229 * Must be in SHELL mode.
231 void minibuffer_add(FilerWindow
*filer_window
, const gchar
*leafname
)
234 GtkEditable
*edit
= GTK_EDITABLE(filer_window
->minibuffer
);
235 GtkEntry
*entry
= GTK_ENTRY(edit
);
238 g_return_if_fail(filer_window
->mini_type
== MINI_SHELL
);
240 esc
= shell_escape(leafname
);
242 gtk_editable_delete_selection(edit
);
243 pos
= gtk_editable_get_position(edit
);
245 if (pos
> 0 && gtk_entry_get_text(entry
)[pos
- 1] != ' ')
246 gtk_editable_insert_text(edit
, " ", 1, &pos
);
248 gtk_editable_insert_text(edit
, esc
, strlen(esc
), &pos
);
249 gtk_editable_set_position(edit
, pos
);
255 /****************************************************************
256 * INTERNAL FUNCTIONS *
257 ****************************************************************/
259 static void show_help(FilerWindow
*filer_window
)
261 switch (filer_window
->mini_type
)
265 _("Enter the name of a file and I'll display "
266 "it for you. Press Tab to fill in the longest "
267 "match. Escape to close the minibuffer."));
271 _("Enter a shell command to execute. Click "
272 "on a file to add it to the buffer."));
274 case MINI_SELECT_BY_NAME
:
276 _("Enter a file name pattern to select all matching files:\n\n"
277 "? means any character\n"
278 "* means zero or more characters\n"
279 "[aA] means 'a' or 'A'\n"
280 "[a-z] means any character from a to z (lowercase)\n"
281 "*.png means any name ending in '.png'"));
284 show_condition_help(NULL
);
288 _("Enter a pattern to match for files to "
289 "be shown. An empty filter turns the "
293 g_warning("Unknown minibuffer type!");
301 static void path_return_pressed(FilerWindow
*filer_window
, GdkEventKey
*event
)
303 const gchar
*path
, *pattern
;
304 int flags
= OPEN_FROM_MINI
| OPEN_SAME_WINDOW
;
308 path
= gtk_entry_get_text(GTK_ENTRY(filer_window
->minibuffer
));
309 pattern
= g_basename(path
);
311 view_get_cursor(filer_window
->view
, &iter
);
313 item
= iter
.peek(&iter
);
314 if (item
== NULL
|| !matches(&iter
, pattern
))
320 if ((event
->state
& GDK_SHIFT_MASK
) != 0)
323 filer_openitem(filer_window
, &iter
, flags
);
326 /* Use the cursor item to fill in the minibuffer.
327 * If there are multiple matches then fill in as much as possible and
330 static void complete(FilerWindow
*filer_window
)
333 DirItem
*item
, *other
;
334 int shortest_stem
= -1;
336 const gchar
*text
, *leaf
;
337 ViewIter cursor
, iter
;
339 view_get_cursor(filer_window
->view
, &cursor
);
340 item
= cursor
.peek(&cursor
);
348 entry
= GTK_ENTRY(filer_window
->minibuffer
);
350 text
= gtk_entry_get_text(entry
);
351 leaf
= strrchr(text
, '/');
359 if (!matches(&cursor
, leaf
))
365 current_stem
= strlen(leaf
);
367 /* Find the longest other match of this name. If it's longer than
368 * the currently entered text then complete only up to that length.
370 view_get_iter(filer_window
->view
, &iter
, 0);
371 while ((other
= iter
.next(&iter
)))
375 if (iter
.i
== cursor
.i
) /* XXX */
378 while (other
->leafname
[stem
] && item
->leafname
[stem
])
381 /* Like the matches() function below, the comparison of
382 * leafs must be case-insensitive.
384 a
= g_ascii_tolower(item
->leafname
[stem
]);
385 b
= g_ascii_tolower(other
->leafname
[stem
]);
391 /* stem is the index of the first difference */
392 if (stem
>= current_stem
&&
393 (shortest_stem
== -1 || stem
< shortest_stem
))
394 shortest_stem
= stem
;
397 if (current_stem
== shortest_stem
)
399 /* We didn't add anything... */
400 if (o_filer_beep_fail
.int_value
)
403 else if (current_stem
< shortest_stem
)
407 /* Have to replace the leafname text in the minibuffer rather
408 * than just append to it. Here's an example:
409 * Suppose we have two dirs, /tmp and /TMP.
410 * The user enters /t in the minibuffer and hits Tab.
411 * With the g_ascii_tolower() code above, this would result
412 * in /tMP being bisplayed in the minibuffer which isn't
413 * intuitive. Therefore all text after the / must be replaced.
415 tmp_pos
= leaf
- text
; /* index of start of leaf */
416 gtk_editable_delete_text(GTK_EDITABLE(entry
),
417 tmp_pos
, entry
->text_length
);
418 gtk_editable_insert_text(GTK_EDITABLE(entry
),
419 item
->leafname
, shortest_stem
,
422 gtk_editable_set_position(GTK_EDITABLE(entry
), -1);
424 if (o_filer_beep_multi
.int_value
)
431 new = make_path(filer_window
->sym_path
, item
->leafname
);
433 if (item
->base_type
== TYPE_DIRECTORY
&&
434 (item
->flags
& ITEM_FLAG_APPDIR
) == 0)
435 new = make_path(new, "");
437 gtk_entry_set_text(entry
, new);
438 gtk_editable_set_position(GTK_EDITABLE(entry
), -1);
442 static void path_changed(FilerWindow
*filer_window
)
444 GtkWidget
*mini
= filer_window
->minibuffer
;
445 const char *rawnew
, *leaf
;
448 gboolean error
= FALSE
;
450 rawnew
= gtk_entry_get_text(GTK_ENTRY(mini
));
453 /* Entry may be blank because we're in the middle of changing
454 * to something else...
456 entry_set_error(mini
, FALSE
);
463 new=g_strdup(rawnew
);
467 if (!rawnew
[1] || rawnew
[1]=='/')
469 new=g_strconcat(g_get_home_dir(), "/",
470 rawnew
[1]? rawnew
+2: "", "/",
477 struct passwd
*passwd
;
480 /* Need to lookup user name */
481 for(sl
=rawnew
+2; *sl
&& *sl
!='/'; sl
++)
483 username
=g_strndup(rawnew
+1, sl
-rawnew
-1);
484 passwd
=getpwnam(username
);
489 new=g_strconcat(passwd
->pw_dir
, "/",
494 new=g_strdup(rawnew
);
499 new=g_strdup(rawnew
);
504 leaf
= g_basename(new);
506 path
= g_strdup("/");
508 path
= g_path_get_dirname(new);
510 if (strcmp(path
, filer_window
->sym_path
) != 0)
512 /* The new path is in a different directory */
515 if (stat_with_timeout(path
, &info
) == 0 &&
516 S_ISDIR(info
.st_mode
))
518 filer_change_to(filer_window
, path
, leaf
);
525 if (*leaf
== '.' && !filer_window
->temp_show_hidden
)
527 filer_window
->temp_show_hidden
= TRUE
;
528 display_update_hidden(filer_window
);
531 if (find_exact_match(filer_window
, leaf
) == FALSE
&&
532 find_next_match(filer_window
, leaf
, 0) == FALSE
)
539 entry_set_error(mini
, error
);
542 /* Look for an exact match, and move the cursor to it if found.
545 static gboolean
find_exact_match(FilerWindow
*filer_window
,
546 const gchar
*pattern
)
550 ViewIface
*view
= filer_window
->view
;
552 view_get_iter(view
, &iter
, 0);
554 while ((item
= iter
.next(&iter
)))
556 if (strcmp(item
->leafname
, pattern
) == 0)
558 view_cursor_to_iter(view
, &iter
);
566 /* Find the next item in the view that matches 'pattern'. Start from
567 * cursor_base and loop at either end. dir is 1 for a forward search,
568 * -1 for backwards. 0 means forwards, but may stay the same.
570 * Does not automatically update cursor_base.
572 * Returns TRUE if a match is found.
574 static gboolean
find_next_match(FilerWindow
*filer_window
,
578 ViewIface
*view
= filer_window
->view
;
581 if (view_count_items(view
) < 1)
584 view_get_iter(view
, &iter
,
585 VIEW_ITER_FROM_BASE
|
586 (dir
>= 0 ? 0 : VIEW_ITER_BACKWARDS
));
589 iter
.next(&iter
); /* Don't look at the base itself */
591 while (iter
.next(&iter
))
593 if (matches(&iter
, pattern
))
595 view_cursor_to_iter(view
, &iter
);
600 /* No matches (except possibly base itself) */
601 view_get_iter(view
, &iter
,
602 VIEW_ITER_FROM_BASE
| VIEW_ITER_ONE_ONLY
|
603 (dir
>= 0 ? 0 : VIEW_ITER_BACKWARDS
));
605 view_cursor_to_iter(view
, &iter
);
610 static gboolean
matches(ViewIter
*iter
, const char *pattern
)
614 item
= iter
->peek(iter
);
616 return strncasecmp(item
->leafname
, pattern
, strlen(pattern
)) == 0;
619 /* Find next match and set base for future matches. */
620 static void search_in_dir(FilerWindow
*filer_window
, int dir
)
622 const char *path
, *pattern
;
625 path
= gtk_entry_get_text(GTK_ENTRY(filer_window
->minibuffer
));
626 pattern
= g_basename(path
);
628 view_get_cursor(filer_window
->view
, &iter
);
629 view_set_base(filer_window
->view
, &iter
);
630 find_next_match(filer_window
, pattern
, dir
);
631 view_get_cursor(filer_window
->view
, &iter
);
632 view_set_base(filer_window
->view
, &iter
);
637 static void add_to_history(const gchar
*line
)
641 last
= shell_history
? (guchar
*) shell_history
->data
: NULL
;
643 if (last
&& strcmp(last
, line
) == 0)
644 return; /* Duplicating last entry */
646 shell_history
= g_list_prepend(shell_history
, g_strdup(line
));
649 static void shell_done(FilerWindow
*filer_window
)
651 if (filer_exists(filer_window
))
652 filer_update_dir(filer_window
, TRUE
);
655 /* Given a list of matches, return the longest stem. g_free() the result.
656 * Special chars are escaped. If there is only a single (non-dir) match
657 * then a trailing space is added.
659 static guchar
*best_match(FilerWindow
*filer_window
, glob_t
*matches
)
661 gchar
*first
= matches
->gl_pathv
[0];
663 int longest
, path_len
;
666 longest
= strlen(first
);
668 for (i
= 1; i
< matches
->gl_pathc
; i
++)
671 guchar
*m
= matches
->gl_pathv
[i
];
673 for (j
= 0; j
< longest
; j
++)
674 if (m
[j
] != first
[j
])
678 path_len
= strlen(filer_window
->sym_path
);
679 if (strncmp(filer_window
->sym_path
, first
, path_len
) == 0 &&
680 first
[path_len
] == '/' && first
[path_len
+ 1])
682 path
= g_strndup(first
+ path_len
+ 1, longest
- path_len
- 1);
685 path
= g_strndup(first
, longest
);
687 tmp
= shell_escape(path
);
690 if (matches
->gl_pathc
== 1 && tmp
[strlen(tmp
) - 1] != '/')
692 path
= g_strdup_printf("%s ", tmp
);
700 static void shell_tab(FilerWindow
*filer_window
)
709 entry
= gtk_entry_get_text(GTK_ENTRY(filer_window
->minibuffer
));
710 pos
= gtk_editable_get_position(GTK_EDITABLE(filer_window
->minibuffer
));
711 leaf
= g_string_new(NULL
);
713 for (i
= 0; i
< pos
; i
++)
722 g_string_truncate(leaf
, 0);
725 else if (c
== '\\' && i
+ 1 < pos
)
727 else if (c
== '"' || c
== '\'')
729 for (++i
; i
< pos
; i
++)
731 guchar cc
= entry
[i
];
733 if (cc
== '\\' && i
+ 1 < pos
)
737 g_string_append_c(leaf
, cc
);
742 g_string_append_c(leaf
, c
);
748 if (leaf
->str
[0] != '/' && leaf
->str
[0] != '~')
750 g_string_prepend_c(leaf
, '/');
751 g_string_prepend(leaf
, filer_window
->sym_path
);
754 g_string_append_c(leaf
, '*');
760 GLOB_MARK
, NULL
, &matches
) == 0)
762 if (matches
.gl_pathc
> 0)
766 GTK_EDITABLE(filer_window
->minibuffer
);
768 best
= best_match(filer_window
, &matches
);
770 gtk_editable_delete_text(edit
, leaf_start
, pos
);
771 gtk_editable_insert_text(edit
, best
, strlen(best
),
773 gtk_editable_set_position(edit
, leaf_start
);
777 if (matches
.gl_pathc
!= 1)
783 g_string_free(leaf
, TRUE
);
786 static void run_child(gpointer unused
)
788 /* Ensure output is noticed - send stdout to stderr */
789 dup2(STDERR_FILENO
, STDOUT_FILENO
);
790 close_on_exec(STDOUT_FILENO
, FALSE
);
793 /* Either execute the command or make it the default run action */
794 static void shell_return_pressed(FilerWindow
*filer_window
)
798 GError
*error
= NULL
;
803 entry
= mini_contents(filer_window
);
808 add_to_history(entry
);
810 argv
= g_ptr_array_new();
811 g_ptr_array_add(argv
, "sh");
812 g_ptr_array_add(argv
, "-c");
813 g_ptr_array_add(argv
, (gchar
*) entry
);
814 g_ptr_array_add(argv
, "sh");
816 view_get_iter(filer_window
->view
, &iter
, 0);
817 while ((item
= iter
.next(&iter
)))
819 if (view_get_selected(filer_window
->view
, &iter
))
820 g_ptr_array_add(argv
, item
->leafname
);
823 g_ptr_array_add(argv
, NULL
);
825 if (!g_spawn_async_with_pipes(filer_window
->sym_path
,
826 (gchar
**) argv
->pdata
, NULL
,
827 G_SPAWN_DO_NOT_REAP_CHILD
|
829 run_child
, NULL
, /* Child setup fn */
830 &child
, /* Child PID */
831 NULL
, NULL
, NULL
, /* Standard pipes */
834 delayed_error("%s", error
? error
->message
: "(null)");
838 on_child_death(child
, (CallbackFn
) shell_done
, filer_window
);
840 g_ptr_array_free(argv
, TRUE
);
843 minibuffer_hide(filer_window
);
846 /* Move through the shell history */
847 static void shell_recall(FilerWindow
*filer_window
, int dir
)
850 int pos
= filer_window
->mini_cursor_base
;
855 command
= g_list_nth_data(shell_history
, pos
);
864 filer_window
->mini_cursor_base
= pos
;
866 gtk_entry_set_text(GTK_ENTRY(filer_window
->minibuffer
), command
);
873 FilerWindow
*filer_window
;
877 static gboolean
select_if_test(ViewIter
*iter
, gpointer user_data
)
880 SelectData
*data
= user_data
;
882 item
= iter
->peek(iter
);
883 g_return_val_if_fail(item
!= NULL
, FALSE
);
885 data
->info
.leaf
= item
->leafname
;
886 data
->info
.fullpath
= make_path(data
->filer_window
->sym_path
,
889 return mc_lstat(data
->info
.fullpath
, &data
->info
.stats
) == 0 &&
890 find_test_condition(data
->cond
, &data
->info
);
893 static void select_return_pressed(FilerWindow
*filer_window
, guint etime
)
898 entry
= mini_contents(filer_window
);
903 add_to_history(entry
);
905 data
.cond
= find_compile(entry
);
908 delayed_error(_("Invalid Find condition"));
912 data
.info
.now
= time(NULL
);
913 data
.info
.prune
= FALSE
; /* (don't care) */
914 data
.filer_window
= filer_window
;
916 view_select_if(filer_window
->view
, select_if_test
, &data
);
918 find_condition_free(data
.cond
);
920 minibuffer_hide(filer_window
);
923 static void filter_return_pressed(FilerWindow
*filer_window
, guint etime
)
927 entry
= mini_contents(filer_window
);
929 if (entry
&& *entry
&& strcmp(entry
, "*")!=0) {
930 display_set_filter(filer_window
, FILER_SHOW_GLOB
,
933 display_set_filter(filer_window
, FILER_SHOW_ALL
, NULL
);
935 minibuffer_hide(filer_window
);
941 static gint
key_press_event(GtkWidget
*widget
,
943 FilerWindow
*filer_window
)
945 if (event
->keyval
== GDK_Escape
)
947 if (filer_window
->mini_type
== MINI_SHELL
)
951 line
= mini_contents(filer_window
);
953 add_to_history(line
);
956 minibuffer_hide(filer_window
);
960 switch (filer_window
->mini_type
)
963 switch (event
->keyval
)
966 search_in_dir(filer_window
, -1);
969 search_in_dir(filer_window
, 1);
973 path_return_pressed(filer_window
,
977 complete(filer_window
);
985 switch (event
->keyval
)
988 shell_recall(filer_window
, 1);
991 shell_recall(filer_window
, -1);
994 shell_tab(filer_window
);
998 shell_return_pressed(filer_window
);
1004 case MINI_SELECT_IF
:
1005 switch (event
->keyval
)
1008 shell_recall(filer_window
, 1);
1011 shell_recall(filer_window
, -1);
1017 select_return_pressed(filer_window
,
1024 case MINI_SELECT_BY_NAME
:
1025 switch (event
->keyval
)
1028 filer_next_selected(filer_window
, -1);
1031 filer_next_selected(filer_window
, 1);
1037 minibuffer_hide(filer_window
);
1045 switch (event
->keyval
)
1049 filter_return_pressed(filer_window
,
1063 static gboolean
select_if_glob(ViewIter
*iter
, gpointer data
)
1066 const char *pattern
= (char *) data
;
1068 item
= iter
->peek(iter
);
1069 g_return_val_if_fail(item
!= NULL
, FALSE
);
1071 return fnmatch(pattern
, item
->leafname
, 0) == 0;
1074 static void changed(GtkEditable
*mini
, FilerWindow
*filer_window
)
1076 switch (filer_window
->mini_type
)
1079 path_changed(filer_window
);
1081 case MINI_SELECT_IF
:
1082 set_find_string_colour(GTK_WIDGET(mini
),
1084 GTK_ENTRY(filer_window
->minibuffer
)));
1086 case MINI_SELECT_BY_NAME
:
1087 view_select_if(filer_window
->view
,
1089 (gpointer
) gtk_entry_get_text(
1090 GTK_ENTRY(filer_window
->minibuffer
)));
1097 /* Returns a string (which must NOT be freed), or NULL if the buffer
1098 * is blank (whitespace only).
1100 static const gchar
*mini_contents(FilerWindow
*filer_window
)
1102 const gchar
*entry
, *c
;
1104 entry
= gtk_entry_get_text(GTK_ENTRY(filer_window
->minibuffer
));
1106 for (c
= entry
; *c
; c
++)
1107 if (!g_ascii_isspace(*c
))
1113 /* This is a really ugly hack to get around Gtk+-2.0's broken auto-select
1116 static gboolean
grab_focus(GtkWidget
*minibuffer
)
1118 GtkWidgetClass
*class;
1120 class = GTK_WIDGET_CLASS(gtk_type_class(GTK_TYPE_WIDGET
));
1122 class->grab_focus(minibuffer
);
1124 g_signal_stop_emission(minibuffer
,
1125 g_signal_lookup("grab_focus", G_OBJECT_TYPE(minibuffer
)), 0);