r1066: Fixed some compiler warnings (Vincent Lef�vre).
[rox-filer.git] / ROX-Filer / src / minibuffer.c
blob63d19f33a3ccf924446b357437fe487a83353658
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* minibuffer.c - for handling the path entry box at the bottom */
24 #include "config.h"
26 #include <string.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <glob.h>
30 #include <stdio.h>
32 #include <gtk/gtk.h>
33 #include <gdk/gdkkeysyms.h>
35 #include "global.h"
37 #include "options.h"
38 #include "collection.h"
39 #include "find.h"
40 #include "gui_support.h"
41 #include "support.h"
42 #include "minibuffer.h"
43 #include "filer.h"
44 #include "display.h"
45 #include "main.h"
46 #include "action.h"
47 #include "diritem.h"
48 #include "type.h"
50 static GList *shell_history = NULL;
52 /* Static prototypes */
53 static gint key_press_event(GtkWidget *widget,
54 GdkEventKey *event,
55 FilerWindow *filer_window);
56 static void changed(GtkEditable *mini, FilerWindow *filer_window);
57 static gboolean find_next_match(FilerWindow *filer_window,
58 char *pattern,
59 int dir);
60 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern);
61 static gboolean matches(Collection *collection, int item, char *pattern);
62 static void search_in_dir(FilerWindow *filer_window, int dir);
63 static guchar *mini_contents(FilerWindow *filer_window);
64 static void show_help(FilerWindow *filer_window);
65 #ifdef GTK2
66 static gboolean grab_focus(GtkWidget *minibuffer);
67 #endif
69 /****************************************************************
70 * EXTERNAL INTERFACE *
71 ****************************************************************/
73 void minibuffer_init(void)
75 option_add_int("filer_beep_fail", 1, NULL);
76 option_add_int("filer_beep_multi", 1, NULL);
79 /* Creates the minibuffer widgets, setting the appropriate fields
80 * in filer_window.
82 void create_minibuffer(FilerWindow *filer_window)
84 GtkWidget *hbox, *label, *mini;
86 hbox = gtk_hbox_new(FALSE, 0);
88 gtk_box_pack_start(GTK_BOX(hbox),
89 new_help_button((HelpFunc) show_help, filer_window),
90 FALSE, TRUE, 0);
92 label = gtk_label_new("");
93 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 2);
95 mini = gtk_entry_new();
96 gtk_box_pack_start(GTK_BOX(hbox), mini, TRUE, TRUE, 0);
97 gtk_widget_set_name(mini, "fixed-style");
98 gtk_signal_connect(GTK_OBJECT(mini), "key_press_event",
99 GTK_SIGNAL_FUNC(key_press_event), filer_window);
100 gtk_signal_connect(GTK_OBJECT(mini), "changed",
101 GTK_SIGNAL_FUNC(changed), filer_window);
103 #ifdef GTK2
104 /* Grabbing focus musn't select the text... */
105 gtk_signal_connect_object(GTK_OBJECT(mini), "grab-focus",
106 GTK_SIGNAL_FUNC(grab_focus),
107 GTK_OBJECT(mini));
108 #endif
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)
117 Collection *collection;
118 GtkEntry *mini;
119 int pos = -1, i;
121 g_return_if_fail(filer_window != NULL);
122 g_return_if_fail(filer_window->minibuffer != NULL);
124 mini = GTK_ENTRY(filer_window->minibuffer);
126 filer_window->mini_type = MINI_NONE;
127 gtk_label_set_text(GTK_LABEL(filer_window->minibuffer_label),
128 mini_type == MINI_PATH ? _("Goto:") :
129 mini_type == MINI_SHELL ? _("Shell:") :
130 mini_type == MINI_SELECT_IF ? _("Select If:") :
131 "?");
133 collection = filer_window->collection;
134 switch (mini_type)
136 case MINI_PATH:
137 collection_move_cursor(collection, 0, 0);
138 filer_window->mini_cursor_base =
139 MAX(collection->cursor_item, 0);
140 gtk_entry_set_text(mini,
141 make_path(filer_window->path, "")->str);
142 if (filer_window->temp_show_hidden)
144 display_set_hidden(filer_window, FALSE);
145 filer_window->temp_show_hidden = FALSE;
147 break;
148 case MINI_SELECT_IF:
149 gtk_entry_set_text(mini, "");
150 filer_window->mini_cursor_base = -1; /* History */
151 break;
152 case MINI_SHELL:
153 pos = 0;
154 i = collection->cursor_item;
155 if (collection->number_selected)
156 gtk_entry_set_text(mini, " \"$@\"");
157 else if (i > -1 && i < collection->number_of_items)
159 DirItem *item = (DirItem *)
160 collection->items[i].data;
161 guchar *tmp;
163 tmp = g_strconcat(" ", item->leafname, NULL);
164 gtk_entry_set_text(mini, tmp);
165 g_free(tmp);
167 else
168 gtk_entry_set_text(mini, "");
169 filer_window->mini_cursor_base = -1; /* History */
170 break;
171 default:
172 g_warning("Bad minibuffer type\n");
173 return;
176 filer_window->mini_type = mini_type;
178 gtk_entry_set_position(mini, pos);
180 gtk_widget_show_all(filer_window->minibuffer_area);
182 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
183 filer_window->minibuffer);
186 void minibuffer_hide(FilerWindow *filer_window)
188 filer_window->mini_type = MINI_NONE;
190 gtk_widget_hide(filer_window->minibuffer_area);
191 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
192 GTK_WIDGET(filer_window->collection));
194 if (filer_window->temp_show_hidden)
196 Collection *collection = filer_window->collection;
197 int i = collection->cursor_item;
198 DirItem *item = NULL;
200 if (i >= 0 && i < collection->number_of_items)
201 item = (DirItem *) collection->items[i].data;
203 if (item == NULL || item->leafname[0] != '.')
204 display_set_hidden(filer_window, FALSE);
205 filer_window->temp_show_hidden = FALSE;
209 /* Insert this leafname at the cursor (replacing the selection, if any).
210 * Must be in SHELL mode.
212 void minibuffer_add(FilerWindow *filer_window, guchar *leafname)
214 guchar *esc;
215 GtkEditable *edit = GTK_EDITABLE(filer_window->minibuffer);
216 GtkEntry *entry = GTK_ENTRY(edit);
217 int pos;
219 g_return_if_fail(filer_window->mini_type == MINI_SHELL);
221 esc = shell_escape(leafname);
223 gtk_editable_delete_selection(edit);
224 pos = gtk_editable_get_position(edit);
226 if (pos > 0 && gtk_entry_get_text(entry)[pos - 1] != ' ')
227 gtk_editable_insert_text(edit, " ", 1, &pos);
229 gtk_editable_insert_text(edit, esc, strlen(esc), &pos);
230 gtk_editable_set_position(edit, pos);
232 g_free(esc);
236 /****************************************************************
237 * INTERNAL FUNCTIONS *
238 ****************************************************************/
240 static void show_help(FilerWindow *filer_window)
242 guchar *message;
244 gtk_widget_grab_focus(filer_window->minibuffer);
246 switch (filer_window->mini_type)
248 case MINI_PATH:
249 message = _("Enter the name of a file and I'll display "
250 "it for you. Press Tab to fill in the longest "
251 "match. Escape to close the minibuffer.");
252 break;
253 case MINI_SHELL:
254 message = _("Enter a shell command to execute. Click "
255 "on a file to add it to the buffer.");
256 break;
257 case MINI_SELECT_IF:
258 show_condition_help(NULL);
259 return;
260 default:
261 message = "?!?";
262 break;
265 delayed_error("%s", message);
269 /* PATH ENTRY */
271 static void path_return_pressed(FilerWindow *filer_window, GdkEventKey *event)
273 Collection *collection = filer_window->collection;
274 int item = collection->cursor_item;
275 char *path, *pattern;
276 int flags = OPEN_FROM_MINI | OPEN_SAME_WINDOW;
278 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
279 pattern = strrchr(path, '/');
280 if (pattern)
281 pattern++;
282 else
283 pattern = path;
285 if (item == -1 || item >= collection->number_of_items ||
286 !matches(collection, item, pattern))
288 gdk_beep();
289 return;
292 if ((event->state & GDK_SHIFT_MASK) != 0)
293 flags |= OPEN_SHIFT;
295 filer_openitem(filer_window, item, flags);
298 /* Use the cursor item to fill in the minibuffer.
299 * If there are multiple matches then fill in as much as possible and
300 * (possibly) beep.
302 static void complete(FilerWindow *filer_window)
304 GtkEntry *entry;
305 Collection *collection = filer_window->collection;
306 int cursor = collection->cursor_item;
307 DirItem *item;
308 int shortest_stem = -1;
309 int current_stem;
310 int other;
311 guchar *text, *leaf;
313 if (cursor < 0 || cursor >= collection->number_of_items)
315 gdk_beep();
316 return;
319 entry = GTK_ENTRY(filer_window->minibuffer);
321 item = (DirItem *) collection->items[cursor].data;
323 text = gtk_entry_get_text(entry);
324 leaf = strrchr(text, '/');
325 if (!leaf)
327 gdk_beep();
328 return;
331 leaf++;
332 if (!matches(collection, cursor, leaf))
334 gdk_beep();
335 return;
338 current_stem = strlen(leaf);
340 /* Find the longest other match of this name. It it's longer than
341 * the currently entered text then complete only up to that length.
343 for (other = 0; other < collection->number_of_items; other++)
345 DirItem *other_item = (DirItem *) collection->items[other].data;
346 int stem = 0;
348 if (other == cursor)
349 continue;
351 while (other_item->leafname[stem] && item->leafname[stem])
353 if (other_item->leafname[stem] != item->leafname[stem])
354 break;
355 stem++;
358 /* stem is the index of the first difference */
359 if (stem >= current_stem &&
360 (shortest_stem == -1 || stem < shortest_stem))
361 shortest_stem = stem;
364 if (current_stem == shortest_stem)
366 /* We didn't add anything... */
367 if (option_get_int("filer_beep_fail"))
368 gdk_beep();
370 else if (current_stem < shortest_stem)
372 guchar *extra;
374 extra = g_strndup(item->leafname + current_stem,
375 shortest_stem - current_stem);
376 gtk_entry_append_text(entry, extra);
377 g_free(extra);
378 #ifdef GTK2
379 gtk_entry_set_position(entry, -1);
380 #endif
382 if (option_get_int("filer_beep_multi"))
383 gdk_beep();
385 else
387 GString *new;
389 new = make_path(filer_window->path, item->leafname);
391 if (item->base_type == TYPE_DIRECTORY &&
392 (item->flags & ITEM_FLAG_APPDIR) == 0)
393 g_string_append_c(new, '/');
395 gtk_entry_set_text(entry, new->str);
396 #ifdef GTK2
397 gtk_entry_set_position(entry, -1);
398 #endif
402 /* This is an idle function because Gtk+ 2.0 changes text in a entry
403 * with two signals; one to blank it and one to put the new text in.
405 static gboolean path_changed(gpointer data)
407 FilerWindow *filer_window = (FilerWindow *) data;
408 GtkWidget *mini = filer_window->minibuffer;
409 char *new, *leaf;
410 char *path, *real;
412 new = gtk_entry_get_text(GTK_ENTRY(mini));
414 leaf = g_basename(new);
415 if (leaf == new)
416 path = g_strdup("/");
417 else
418 path = g_dirname(new);
419 real = pathdup(path);
420 g_free(path);
422 if (strcmp(real, filer_window->path) != 0)
424 /* The new path is in a different directory */
425 struct stat info;
427 if (mc_stat(real, &info) == 0 && S_ISDIR(info.st_mode))
428 filer_change_to(filer_window, real, leaf);
429 else
430 gdk_beep();
432 else
434 if (*leaf == '.')
436 if (!filer_window->show_hidden)
438 filer_window->temp_show_hidden = TRUE;
439 display_set_hidden(filer_window, TRUE);
442 else if (filer_window->temp_show_hidden)
444 display_set_hidden(filer_window, FALSE);
445 filer_window->temp_show_hidden = FALSE;
448 if (find_exact_match(filer_window, leaf) == FALSE &&
449 find_next_match(filer_window, leaf, 0) == FALSE)
450 gdk_beep();
453 g_free(real);
455 return FALSE;
458 /* Look for an exact match, and move the cursor to it if found.
459 * TRUE on success.
461 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern)
463 Collection *collection = filer_window->collection;
464 int i;
466 for (i = 0; i < collection->number_of_items; i++)
468 DirItem *item = (DirItem *) collection->items[i].data;
470 if (strcmp(item->leafname, pattern) == 0)
472 collection_set_cursor_item(collection, i);
473 return TRUE;
477 return FALSE;
480 /* Find the next item in the collection that matches 'pattern'. Start from
481 * mini_cursor_base and loop at either end. dir is 1 for a forward search,
482 * -1 for backwards. 0 means forwards, but may stay the same.
484 * Does not automatically update mini_cursor_base.
486 * Returns TRUE if a match is found.
488 static gboolean find_next_match(FilerWindow *filer_window,
489 char *pattern,
490 int dir)
492 Collection *collection = filer_window->collection;
493 int base = filer_window->mini_cursor_base;
494 int item = base;
495 gboolean retval = TRUE;
497 if (collection->number_of_items < 1)
498 return FALSE;
500 if (base < 0 || base>= collection->number_of_items)
501 filer_window->mini_cursor_base = base = 0;
505 /* Step to the next item */
506 item += dir;
508 if (item >= collection->number_of_items)
509 item = 0;
510 else if (item < 0)
511 item = collection->number_of_items - 1;
513 if (dir == 0)
514 dir = 1;
515 else if (item == base)
517 retval = FALSE;
518 break; /* No (other) matches at all */
520 } while (!matches(collection, item, pattern));
522 collection_set_cursor_item(collection, item);
524 return retval;
527 static gboolean matches(Collection *collection, int item_number, char *pattern)
529 DirItem *item = (DirItem *) collection->items[item_number].data;
531 return strncmp(item->leafname, pattern, strlen(pattern)) == 0;
534 /* Find next match and set base for future matches. */
535 static void search_in_dir(FilerWindow *filer_window, int dir)
537 char *path, *pattern;
539 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
540 pattern = strrchr(path, '/');
541 if (pattern)
542 pattern++;
543 else
544 pattern = path;
546 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
547 find_next_match(filer_window, pattern, dir);
548 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
551 /* SHELL COMMANDS */
553 static void add_to_history(guchar *line)
555 guchar *last;
557 last = shell_history ? (guchar *) shell_history->data : NULL;
559 if (last && strcmp(last, line) == 0)
560 return; /* Duplicating last entry */
562 shell_history = g_list_prepend(shell_history, g_strdup(line));
565 static void shell_done(FilerWindow *filer_window)
567 if (filer_exists(filer_window))
568 filer_update_dir(filer_window, TRUE);
571 /* Given a list of matches, return the longest stem. g_free() the result.
572 * Special chars are escaped. If there is only a single (non-dir) match
573 * then a trailing space is added.
575 static guchar *best_match(FilerWindow *filer_window, glob_t *matches)
577 gchar *first = matches->gl_pathv[0];
578 int i;
579 int longest, path_len;
580 guchar *path, *tmp;
582 longest = strlen(first);
584 for (i = 1; i < matches->gl_pathc; i++)
586 int j;
587 guchar *m = matches->gl_pathv[i];
589 for (j = 0; j < longest; j++)
590 if (m[j] != first[j])
591 longest = j;
594 path_len = strlen(filer_window->path);
595 if (strncmp(filer_window->path, first, path_len) == 0 &&
596 first[path_len] == '/' && first[path_len + 1])
598 path = g_strndup(first + path_len + 1, longest - path_len - 1);
600 else
601 path = g_strndup(first, longest);
603 tmp = shell_escape(path);
604 g_free(path);
606 if (matches->gl_pathc == 1 && tmp[strlen(tmp) - 1] != '/')
608 path = g_strdup_printf("%s ", tmp);
609 g_free(tmp);
610 return path;
613 return tmp;
616 static void shell_tab(FilerWindow *filer_window)
618 int i;
619 guchar *entry;
620 guchar quote;
621 int pos;
622 GString *leaf;
623 glob_t matches;
624 int leaf_start;
626 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
627 pos = gtk_editable_get_position(GTK_EDITABLE(filer_window->minibuffer));
628 leaf = g_string_new(NULL);
630 quote = '\0';
631 for (i = 0; i < pos; i++)
633 guchar c = entry[i];
635 if (leaf->len == 0)
636 leaf_start = i;
638 if (c == ' ')
640 g_string_truncate(leaf, 0);
641 continue;
643 else if (c == '\\' && i + 1 < pos)
644 c = entry[++i];
645 else if (c == '"' || c == '\'')
647 guchar cc;
649 for (++i; i < pos; i++)
651 cc = entry[i];
653 if (cc == '\\' && i + 1 < pos)
654 cc = entry[++i];
655 else if (entry[i] == c)
656 break;
657 g_string_append_c(leaf, entry[i]);
659 continue;
662 g_string_append_c(leaf, c);
665 if (leaf->len == 0)
666 leaf_start = pos;
668 if (leaf->str[0] != '/' && leaf->str[0] != '~')
670 g_string_prepend_c(leaf, '/');
671 g_string_prepend(leaf, filer_window->path);
674 g_string_append_c(leaf, '*');
676 if (glob(leaf->str,
677 #ifdef GLOB_TILDE
678 GLOB_TILDE |
679 #endif
680 GLOB_MARK, NULL, &matches) == 0)
682 if (matches.gl_pathc > 0)
684 guchar *best;
685 GtkEditable *edit =
686 GTK_EDITABLE(filer_window->minibuffer);
688 best = best_match(filer_window, &matches);
690 gtk_editable_delete_text(edit, leaf_start, pos);
691 gtk_editable_insert_text(edit, best, strlen(best),
692 &leaf_start);
693 gtk_editable_set_position(edit, leaf_start);
695 g_free(best);
697 if (matches.gl_pathc != 1)
698 gdk_beep();
700 globfree(&matches);
703 g_string_free(leaf, TRUE);
706 /* Either execute the command or make it the default run action */
707 static void shell_return_pressed(FilerWindow *filer_window)
709 GPtrArray *argv;
710 int i;
711 guchar *entry;
712 Collection *collection = filer_window->collection;
713 int child;
715 entry = mini_contents(filer_window);
717 if (!entry)
718 goto out;
720 add_to_history(entry);
722 argv = g_ptr_array_new();
723 g_ptr_array_add(argv, "sh");
724 g_ptr_array_add(argv, "-c");
725 g_ptr_array_add(argv, entry);
726 g_ptr_array_add(argv, "sh");
728 for (i = 0; i < collection->number_of_items; i++)
730 DirItem *item = (DirItem *) collection->items[i].data;
731 if (collection->items[i].selected)
732 g_ptr_array_add(argv, item->leafname);
735 g_ptr_array_add(argv, NULL);
737 child = fork();
739 switch (child)
741 case -1:
742 delayed_error(_("Failed to create child process"));
743 break;
744 case 0: /* Child */
745 /* Ensure output is noticed - send stdout to stderr */
746 dup2(STDERR_FILENO, STDOUT_FILENO);
747 close_on_exec(STDOUT_FILENO, FALSE);
748 if (chdir(filer_window->path))
749 g_printerr("chdir(%s) failed: %s\n",
750 filer_window->path,
751 g_strerror(errno));
752 execvp((char *) argv->pdata[0],
753 (char **) argv->pdata);
754 g_printerr("execvp(%s, ...) failed: %s\n",
755 (char *) argv->pdata[0],
756 g_strerror(errno));
757 _exit(0);
758 default:
759 on_child_death(child,
760 (CallbackFn) shell_done, filer_window);
761 break;
764 g_ptr_array_free(argv, TRUE);
766 out:
767 minibuffer_hide(filer_window);
770 /* Move through the shell history */
771 static void shell_recall(FilerWindow *filer_window, int dir)
773 guchar *command;
774 int pos = filer_window->mini_cursor_base;
776 pos += dir;
777 if (pos >= 0)
779 command = g_list_nth_data(shell_history, pos);
780 if (!command)
781 return;
783 else
784 command = "";
786 if (pos < -1)
787 pos = -1;
788 filer_window->mini_cursor_base = pos;
790 gtk_entry_set_text(GTK_ENTRY(filer_window->minibuffer), command);
793 /* SELECT IF */
795 static void select_return_pressed(FilerWindow *filer_window, guint etime)
797 FindCondition *cond;
798 int i, n;
799 guchar *entry;
800 Collection *collection = filer_window->collection;
801 FindInfo info;
803 entry = mini_contents(filer_window);
805 if (!entry)
806 goto out;
808 add_to_history(entry);
810 cond = find_compile(entry);
811 if (!cond)
813 delayed_error(_("Invalid Find condition"));
814 return;
817 info.now = time(NULL);
818 info.prune = FALSE; /* (don't care) */
819 n = collection->number_of_items;
821 collection->block_selection_changed++;
823 /* If an item at the start is selected then we could lose the
824 * primary selection after checking that item and then need to
825 * gain it again at the end. Therefore, if anything is selected
826 * then select the last item until the end of the search.
828 if (collection->number_selected)
829 collection_select_item(collection, n - 1);
831 for (i = 0; i < n; i++)
833 DirItem *item = (DirItem *) collection->items[i].data;
835 info.leaf = item->leafname;
836 info.fullpath = make_path(filer_window->path, info.leaf)->str;
838 if (lstat(info.fullpath, &info.stats) == 0 &&
839 find_test_condition(cond, &info))
840 collection_select_item(collection, i);
841 else
842 collection_unselect_item(collection, i);
845 find_condition_free(cond);
847 collection_unblock_selection_changed(collection, etime, TRUE);
848 out:
849 minibuffer_hide(filer_window);
853 /* EVENT HANDLERS */
855 static gint key_press_event(GtkWidget *widget,
856 GdkEventKey *event,
857 FilerWindow *filer_window)
859 if (event->keyval == GDK_Escape)
861 if (filer_window->mini_type == MINI_SHELL)
863 guchar *line;
865 line = mini_contents(filer_window);
866 if (line)
867 add_to_history(line);
870 minibuffer_hide(filer_window);
871 return TRUE;
874 switch (filer_window->mini_type)
876 case MINI_PATH:
877 switch (event->keyval)
879 case GDK_Up:
880 search_in_dir(filer_window, -1);
881 break;
882 case GDK_Down:
883 search_in_dir(filer_window, 1);
884 break;
885 case GDK_Return:
886 case GDK_KP_Enter:
887 path_return_pressed(filer_window,
888 event);
889 break;
890 case GDK_Tab:
891 complete(filer_window);
892 break;
893 default:
894 return FALSE;
896 break;
898 case MINI_SHELL:
899 switch (event->keyval)
901 case GDK_Up:
902 shell_recall(filer_window, 1);
903 break;
904 case GDK_Down:
905 shell_recall(filer_window, -1);
906 break;
907 case GDK_Tab:
908 shell_tab(filer_window);
909 break;
910 case GDK_Return:
911 case GDK_KP_Enter:
912 shell_return_pressed(filer_window);
913 break;
914 default:
915 return FALSE;
917 break;
918 case MINI_SELECT_IF:
919 switch (event->keyval)
921 case GDK_Up:
922 shell_recall(filer_window, 1);
923 break;
924 case GDK_Down:
925 shell_recall(filer_window, -1);
926 break;
927 case GDK_Tab:
928 break;
929 case GDK_Return:
930 case GDK_KP_Enter:
931 select_return_pressed(filer_window,
932 event->time);
933 break;
934 default:
935 return FALSE;
937 break;
938 default:
939 break;
942 #ifndef GTK2
943 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
944 #endif
945 return TRUE;
948 static void changed(GtkEditable *mini, FilerWindow *filer_window)
950 switch (filer_window->mini_type)
952 case MINI_PATH:
953 gtk_idle_add(path_changed, filer_window);
954 return;
955 case MINI_SELECT_IF:
956 set_find_string_colour(GTK_WIDGET(mini),
957 gtk_entry_get_text(
958 GTK_ENTRY(filer_window->minibuffer)));
959 return;
960 default:
961 break;
965 /* Returns a string (which must NOT be freed), or NULL if the buffer
966 * is blank (whitespace only).
968 static guchar *mini_contents(FilerWindow *filer_window)
970 guchar *entry, *c;
972 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
974 for (c = entry; *c; c++)
975 if (!isspace(*c))
976 return entry;
978 return NULL;
981 #ifdef GTK2
982 static gboolean grab_focus(GtkWidget *minibuffer)
984 GtkWidgetClass *class;
986 class = GTK_WIDGET_CLASS(gtk_type_class(GTK_TYPE_WIDGET));
988 class->grab_focus(minibuffer);
990 gtk_signal_emit_stop_by_name(GTK_OBJECT(minibuffer), "grab_focus");
992 return 1;
994 #endif