r898: Applied Bernard Jungen's latest patch:
[rox-filer.git] / ROX-Filer / src / minibuffer.c
blobf2abd7ec5b12a609e32ca857b2e69e83d9966e4a
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2001, 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 "main.h"
45 #include "action.h"
46 #include "dir.h"
47 #include "type.h"
49 static GList *shell_history = NULL;
51 /* Static prototypes */
52 static gint key_press_event(GtkWidget *widget,
53 GdkEventKey *event,
54 FilerWindow *filer_window);
55 static void changed(GtkEditable *mini, FilerWindow *filer_window);
56 static gboolean find_next_match(FilerWindow *filer_window,
57 char *pattern,
58 int dir);
59 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern);
60 static gboolean matches(Collection *collection, int item, char *pattern);
61 static void search_in_dir(FilerWindow *filer_window, int dir);
62 static guchar *mini_contents(FilerWindow *filer_window);
63 static void show_help(FilerWindow *filer_window);
66 /****************************************************************
67 * EXTERNAL INTERFACE *
68 ****************************************************************/
70 void minibuffer_init(void)
72 option_add_int("filer_beep_fail", 1, NULL);
73 option_add_int("filer_beep_multi", 1, NULL);
76 /* Creates the minibuffer widgets, setting the appropriate fields
77 * in filer_window.
79 void create_minibuffer(FilerWindow *filer_window)
81 GtkWidget *hbox, *label, *mini;
83 hbox = gtk_hbox_new(FALSE, 0);
85 gtk_box_pack_start(GTK_BOX(hbox),
86 new_help_button((HelpFunc) show_help, filer_window),
87 FALSE, TRUE, 0);
89 label = gtk_label_new("");
90 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 2);
92 mini = gtk_entry_new();
93 gtk_box_pack_start(GTK_BOX(hbox), mini, TRUE, TRUE, 0);
94 gtk_widget_set_style(mini, fixed_style);
95 gtk_signal_connect(GTK_OBJECT(mini), "key_press_event",
96 GTK_SIGNAL_FUNC(key_press_event), filer_window);
97 gtk_signal_connect(GTK_OBJECT(mini), "changed",
98 GTK_SIGNAL_FUNC(changed), filer_window);
100 filer_window->minibuffer = mini;
101 filer_window->minibuffer_label = label;
102 filer_window->minibuffer_area = hbox;
105 void minibuffer_show(FilerWindow *filer_window, MiniType mini_type)
107 Collection *collection;
108 GtkEntry *mini;
109 int pos = -1, i;
111 g_return_if_fail(filer_window != NULL);
112 g_return_if_fail(filer_window->minibuffer != NULL);
114 mini = GTK_ENTRY(filer_window->minibuffer);
115 gtk_widget_set_style(filer_window->minibuffer, fixed_style);
117 filer_window->mini_type = MINI_NONE;
118 gtk_label_set_text(GTK_LABEL(filer_window->minibuffer_label),
119 mini_type == MINI_PATH ? _("Goto:") :
120 mini_type == MINI_SHELL ? _("Shell:") :
121 mini_type == MINI_SELECT_IF ? _("Select If:") :
122 "?");
124 collection = filer_window->collection;
125 switch (mini_type)
127 case MINI_PATH:
128 collection_move_cursor(collection, 0, 0);
129 filer_window->mini_cursor_base =
130 MAX(collection->cursor_item, 0);
131 gtk_entry_set_text(mini,
132 make_path(filer_window->path, "")->str);
133 if (filer_window->temp_show_hidden)
135 display_set_hidden(filer_window, FALSE);
136 filer_window->temp_show_hidden = FALSE;
138 break;
139 case MINI_SELECT_IF:
140 gtk_entry_set_text(mini, "");
141 filer_window->mini_cursor_base = -1; /* History */
142 break;
143 case MINI_SHELL:
144 pos = 0;
145 i = collection->cursor_item;
146 if (collection->number_selected)
147 gtk_entry_set_text(mini, " \"$@\"");
148 else if (i > -1 && i < collection->number_of_items)
150 DirItem *item = (DirItem *)
151 collection->items[i].data;
152 guchar *tmp;
154 tmp = g_strconcat(" ", item->leafname, NULL);
155 gtk_entry_set_text(mini, tmp);
156 g_free(tmp);
158 else
159 gtk_entry_set_text(mini, "");
160 filer_window->mini_cursor_base = -1; /* History */
161 break;
162 default:
163 g_warning("Bad minibuffer type\n");
164 return;
167 filer_window->mini_type = mini_type;
169 gtk_entry_set_position(mini, pos);
171 gtk_widget_show_all(filer_window->minibuffer_area);
173 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
174 filer_window->minibuffer);
177 void minibuffer_hide(FilerWindow *filer_window)
179 filer_window->mini_type = MINI_NONE;
181 gtk_widget_hide(filer_window->minibuffer_area);
182 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
183 GTK_WIDGET(filer_window->collection));
185 if (filer_window->temp_show_hidden)
187 display_set_hidden(filer_window, FALSE);
188 filer_window->temp_show_hidden = FALSE;
192 /* Insert this leafname at the cursor (replacing the selection, if any).
193 * Must be in SHELL mode.
195 void minibuffer_add(FilerWindow *filer_window, guchar *leafname)
197 guchar *esc;
198 GtkEditable *edit = GTK_EDITABLE(filer_window->minibuffer);
199 GtkEntry *entry = GTK_ENTRY(edit);
200 int pos;
202 g_return_if_fail(filer_window->mini_type == MINI_SHELL);
204 esc = shell_escape(leafname);
206 gtk_editable_delete_selection(edit);
207 pos = gtk_editable_get_position(edit);
209 if (pos > 0 && gtk_entry_get_text(entry)[pos - 1] != ' ')
210 gtk_editable_insert_text(edit, " ", 1, &pos);
212 gtk_editable_insert_text(edit, esc, strlen(esc), &pos);
213 gtk_editable_set_position(edit, pos);
215 g_free(esc);
219 /****************************************************************
220 * INTERNAL FUNCTIONS *
221 ****************************************************************/
223 static void show_help(FilerWindow *filer_window)
225 guchar *message;
227 gtk_widget_grab_focus(filer_window->minibuffer);
229 switch (filer_window->mini_type)
231 case MINI_PATH:
232 message = _("Enter the name of a file and I'll display "
233 "it for you. Press Tab to fill in the longest "
234 "match. Escape to close the minibuffer.");
235 break;
236 case MINI_SHELL:
237 message = _("Enter a shell command to execute. Click "
238 "on a file to add it to the buffer.");
239 break;
240 case MINI_SELECT_IF:
241 show_condition_help(NULL);
242 return;
243 default:
244 message = "?!?";
245 break;
248 delayed_rox_error("%s", message);
252 /* PATH ENTRY */
254 static void path_return_pressed(FilerWindow *filer_window, GdkEventKey *event)
256 Collection *collection = filer_window->collection;
257 int item = collection->cursor_item;
258 char *path, *pattern;
259 int flags = OPEN_FROM_MINI | OPEN_SAME_WINDOW;
261 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
262 pattern = strrchr(path, '/');
263 if (pattern)
264 pattern++;
265 else
266 pattern = path;
268 if (item == -1 || item >= collection->number_of_items ||
269 !matches(collection, item, pattern))
271 gdk_beep();
272 return;
275 if ((event->state & GDK_SHIFT_MASK) != 0)
276 flags |= OPEN_SHIFT;
278 filer_openitem(filer_window, item, flags);
281 /* Use the cursor item to fill in the minibuffer.
282 * If there are multiple matches then fill in as much as possible and
283 * (possibly) beep.
285 static void complete(FilerWindow *filer_window)
287 GtkEntry *entry;
288 Collection *collection = filer_window->collection;
289 int cursor = collection->cursor_item;
290 DirItem *item;
291 int shortest_stem = -1;
292 int current_stem;
293 int other;
294 guchar *text, *leaf;
296 if (cursor < 0 || cursor >= collection->number_of_items)
298 gdk_beep();
299 return;
302 entry = GTK_ENTRY(filer_window->minibuffer);
304 item = (DirItem *) collection->items[cursor].data;
306 text = gtk_entry_get_text(entry);
307 leaf = strrchr(text, '/');
308 if (!leaf)
310 gdk_beep();
311 return;
314 leaf++;
315 if (!matches(collection, cursor, leaf))
317 gdk_beep();
318 return;
321 current_stem = strlen(leaf);
323 /* Find the longest other match of this name. It it's longer than
324 * the currently entered text then complete only up to that length.
326 for (other = 0; other < collection->number_of_items; other++)
328 DirItem *other_item = (DirItem *) collection->items[other].data;
329 int stem = 0;
331 if (other == cursor)
332 continue;
334 while (other_item->leafname[stem] && item->leafname[stem])
336 if (other_item->leafname[stem] != item->leafname[stem])
337 break;
338 stem++;
341 /* stem is the index of the first difference */
342 if (stem >= current_stem &&
343 (shortest_stem == -1 || stem < shortest_stem))
344 shortest_stem = stem;
347 if (current_stem == shortest_stem)
349 /* We didn't add anything... */
350 if (option_get_int("filer_beep_fail"))
351 gdk_beep();
353 else if (current_stem < shortest_stem)
355 guchar *extra;
357 extra = g_strndup(item->leafname + current_stem,
358 shortest_stem - current_stem);
359 gtk_entry_append_text(entry, extra);
360 g_free(extra);
361 #ifdef GTK2
362 gtk_entry_set_position(entry, -1);
363 #endif
365 if (option_get_int("filer_beep_multi"))
366 gdk_beep();
368 else
370 GString *new;
372 new = make_path(filer_window->path, item->leafname);
374 if (item->base_type == TYPE_DIRECTORY &&
375 (item->flags & ITEM_FLAG_APPDIR) == 0)
376 g_string_append_c(new, '/');
378 gtk_entry_set_text(entry, new->str);
379 #ifdef GTK2
380 gtk_entry_set_position(entry, -1);
381 #endif
385 /* This is an idle function because Gtk+ 2.0 changes text in a entry
386 * with two signals; one to blank it and one to put the new text in.
388 static gboolean path_changed(gpointer data)
390 FilerWindow *filer_window = (FilerWindow *) data;
391 GtkWidget *mini = filer_window->minibuffer;
392 char *new, *leaf;
393 char *path, *real;
395 new = gtk_entry_get_text(GTK_ENTRY(mini));
397 leaf = g_basename(new);
398 if (leaf == new)
399 path = g_strdup("/");
400 else
401 path = g_dirname(new);
402 real = pathdup(path);
403 g_free(path);
405 if (strcmp(real, filer_window->path) != 0)
407 /* The new path is in a different directory */
408 struct stat info;
410 if (mc_stat(real, &info) == 0 && S_ISDIR(info.st_mode))
411 filer_change_to(filer_window, real, leaf);
412 else
413 gdk_beep();
415 else
417 if (*leaf == '.')
419 if (!filer_window->show_hidden)
421 filer_window->temp_show_hidden = TRUE;
422 display_set_hidden(filer_window, TRUE);
425 else if (filer_window->temp_show_hidden)
427 display_set_hidden(filer_window, FALSE);
428 filer_window->temp_show_hidden = FALSE;
431 if (find_exact_match(filer_window, leaf) == FALSE &&
432 find_next_match(filer_window, leaf, 0) == FALSE)
433 gdk_beep();
436 g_free(real);
438 return FALSE;
441 /* Look for an exact match, and move the cursor to it if found.
442 * TRUE on success.
444 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern)
446 Collection *collection = filer_window->collection;
447 int i;
449 for (i = 0; i < collection->number_of_items; i++)
451 DirItem *item = (DirItem *) collection->items[i].data;
453 if (strcmp(item->leafname, pattern) == 0)
455 collection_set_cursor_item(collection, i);
456 return TRUE;
460 return FALSE;
463 /* Find the next item in the collection that matches 'pattern'. Start from
464 * mini_cursor_base and loop at either end. dir is 1 for a forward search,
465 * -1 for backwards. 0 means forwards, but may stay the same.
467 * Does not automatically update mini_cursor_base.
469 * Returns TRUE if a match is found.
471 static gboolean find_next_match(FilerWindow *filer_window,
472 char *pattern,
473 int dir)
475 Collection *collection = filer_window->collection;
476 int base = filer_window->mini_cursor_base;
477 int item = base;
478 gboolean retval = TRUE;
480 if (collection->number_of_items < 1)
481 return FALSE;
483 if (base < 0 || base>= collection->number_of_items)
484 filer_window->mini_cursor_base = base = 0;
488 /* Step to the next item */
489 item += dir;
491 if (item >= collection->number_of_items)
492 item = 0;
493 else if (item < 0)
494 item = collection->number_of_items - 1;
496 if (dir == 0)
497 dir = 1;
498 else if (item == base)
500 retval = FALSE;
501 break; /* No (other) matches at all */
503 } while (!matches(collection, item, pattern));
505 collection_set_cursor_item(collection, item);
507 return retval;
510 static gboolean matches(Collection *collection, int item_number, char *pattern)
512 DirItem *item = (DirItem *) collection->items[item_number].data;
514 return strncmp(item->leafname, pattern, strlen(pattern)) == 0;
517 /* Find next match and set base for future matches. */
518 static void search_in_dir(FilerWindow *filer_window, int dir)
520 char *path, *pattern;
522 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
523 pattern = strrchr(path, '/');
524 if (pattern)
525 pattern++;
526 else
527 pattern = path;
529 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
530 find_next_match(filer_window, pattern, dir);
531 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
534 /* SHELL COMMANDS */
536 static void add_to_history(guchar *line)
538 guchar *last;
540 last = shell_history ? (guchar *) shell_history->data : NULL;
542 if (last && strcmp(last, line) == 0)
543 return; /* Duplicating last entry */
545 shell_history = g_list_prepend(shell_history, g_strdup(line));
548 static void shell_done(FilerWindow *filer_window)
550 if (filer_exists(filer_window))
551 filer_update_dir(filer_window, TRUE);
554 /* Given a list of matches, return the longest stem. g_free() the result.
555 * Special chars are escaped. If there is only a single (non-dir) match
556 * then a trailing space is added.
558 static guchar *best_match(FilerWindow *filer_window, glob_t *matches)
560 gchar *first = matches->gl_pathv[0];
561 int i;
562 int longest, path_len;
563 guchar *path, *tmp;
565 longest = strlen(first);
567 for (i = 1; i < matches->gl_pathc; i++)
569 int j;
570 guchar *m = matches->gl_pathv[i];
572 for (j = 0; j < longest; j++)
573 if (m[j] != first[j])
574 longest = j;
577 path_len = strlen(filer_window->path);
578 if (strncmp(filer_window->path, first, path_len) == 0 &&
579 first[path_len] == '/' && first[path_len + 1])
581 path = g_strndup(first + path_len + 1, longest - path_len - 1);
583 else
584 path = g_strndup(first, longest);
586 tmp = shell_escape(path);
587 g_free(path);
589 if (matches->gl_pathc == 1 && tmp[strlen(tmp) - 1] != '/')
591 path = g_strdup_printf("%s ", tmp);
592 g_free(tmp);
593 return path;
596 return tmp;
599 static void shell_tab(FilerWindow *filer_window)
601 int i;
602 guchar *entry;
603 guchar quote;
604 int pos;
605 GString *leaf;
606 glob_t matches;
607 int leaf_start;
609 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
610 pos = gtk_editable_get_position(GTK_EDITABLE(filer_window->minibuffer));
611 leaf = g_string_new(NULL);
613 quote = '\0';
614 for (i = 0; i < pos; i++)
616 guchar c = entry[i];
618 if (leaf->len == 0)
619 leaf_start = i;
621 if (c == ' ')
623 g_string_truncate(leaf, 0);
624 continue;
626 else if (c == '\\' && i + 1 < pos)
627 c = entry[++i];
628 else if (c == '"' || c == '\'')
630 guchar cc;
632 for (++i; i < pos; i++)
634 cc = entry[i];
636 if (cc == '\\' && i + 1 < pos)
637 cc = entry[++i];
638 else if (entry[i] == c)
639 break;
640 g_string_append_c(leaf, entry[i]);
642 continue;
645 g_string_append_c(leaf, c);
648 if (leaf->len == 0)
649 leaf_start = pos;
651 if (leaf->str[0] != '/' && leaf->str[0] != '~')
653 g_string_prepend_c(leaf, '/');
654 g_string_prepend(leaf, filer_window->path);
657 g_string_append_c(leaf, '*');
659 if (glob(leaf->str,
660 #ifdef GLOB_TILDE
661 GLOB_TILDE |
662 #endif
663 GLOB_MARK, NULL, &matches) == 0)
665 if (matches.gl_pathc > 0)
667 guchar *best;
668 GtkEditable *edit =
669 GTK_EDITABLE(filer_window->minibuffer);
671 best = best_match(filer_window, &matches);
673 gtk_editable_delete_text(edit, leaf_start, pos);
674 gtk_editable_insert_text(edit, best, strlen(best),
675 &leaf_start);
676 gtk_editable_set_position(edit, leaf_start);
678 g_free(best);
680 if (matches.gl_pathc != 1)
681 gdk_beep();
683 globfree(&matches);
686 g_string_free(leaf, TRUE);
689 /* Either execute the command or make it the default run action */
690 static void shell_return_pressed(FilerWindow *filer_window)
692 GPtrArray *argv;
693 int i;
694 guchar *entry;
695 Collection *collection = filer_window->collection;
696 int child;
698 entry = mini_contents(filer_window);
700 if (!entry)
701 goto out;
703 add_to_history(entry);
705 argv = g_ptr_array_new();
706 g_ptr_array_add(argv, "sh");
707 g_ptr_array_add(argv, "-c");
708 g_ptr_array_add(argv, entry);
709 g_ptr_array_add(argv, "sh");
711 for (i = 0; i < collection->number_of_items; i++)
713 DirItem *item = (DirItem *) collection->items[i].data;
714 if (collection->items[i].selected)
715 g_ptr_array_add(argv, item->leafname);
718 g_ptr_array_add(argv, NULL);
720 child = fork();
722 switch (child)
724 case -1:
725 delayed_rox_error(_("Failed to create child process"));
726 break;
727 case 0: /* Child */
728 /* Ensure output is noticed - send stdout to stderr */
729 dup2(STDERR_FILENO, STDOUT_FILENO);
730 close_on_exec(STDOUT_FILENO, FALSE);
731 if (chdir(filer_window->path))
732 g_printerr("chdir(%s) failed: %s\n",
733 filer_window->path,
734 g_strerror(errno));
735 execvp((char *) argv->pdata[0],
736 (char **) argv->pdata);
737 g_printerr("execvp(%s, ...) failed: %s\n",
738 (char *) argv->pdata[0],
739 g_strerror(errno));
740 _exit(0);
741 default:
742 on_child_death(child,
743 (CallbackFn) shell_done, filer_window);
744 break;
747 g_ptr_array_free(argv, TRUE);
749 out:
750 minibuffer_hide(filer_window);
753 /* Move through the shell history */
754 static void shell_recall(FilerWindow *filer_window, int dir)
756 guchar *command;
757 int pos = filer_window->mini_cursor_base;
759 pos += dir;
760 if (pos >= 0)
762 command = g_list_nth_data(shell_history, pos);
763 if (!command)
764 return;
766 else
767 command = "";
769 if (pos < -1)
770 pos = -1;
771 filer_window->mini_cursor_base = pos;
773 gtk_entry_set_text(GTK_ENTRY(filer_window->minibuffer), command);
776 /* SELECT IF */
778 static void select_return_pressed(FilerWindow *filer_window, guint etime)
780 FindCondition *cond;
781 int i, n;
782 guchar *entry;
783 Collection *collection = filer_window->collection;
784 FindInfo info;
786 entry = mini_contents(filer_window);
788 if (!entry)
789 goto out;
791 add_to_history(entry);
793 cond = find_compile(entry);
794 if (!cond)
796 delayed_rox_error(_("Invalid Find condition"));
797 return;
800 info.now = time(NULL);
801 info.prune = FALSE; /* (don't care) */
802 n = collection->number_of_items;
804 collection->block_selection_changed++;
806 /* If an item at the start is selected then we could lose the
807 * primary selection after checking that item and then need to
808 * gain it again at the end. Therefore, if anything is selected
809 * then select the last item until the end of the search.
811 if (collection->number_selected)
812 collection_select_item(collection, n - 1);
814 for (i = 0; i < n; i++)
816 DirItem *item = (DirItem *) collection->items[i].data;
818 info.leaf = item->leafname;
819 info.fullpath = make_path(filer_window->path, info.leaf)->str;
821 if (lstat(info.fullpath, &info.stats) == 0 &&
822 find_test_condition(cond, &info))
823 collection_select_item(collection, i);
824 else
825 collection_unselect_item(collection, i);
828 find_condition_free(cond);
830 collection_unblock_selection_changed(collection, etime, TRUE);
831 out:
832 minibuffer_hide(filer_window);
836 /* EVENT HANDLERS */
838 static gint key_press_event(GtkWidget *widget,
839 GdkEventKey *event,
840 FilerWindow *filer_window)
842 if (event->keyval == GDK_Escape)
844 if (filer_window->mini_type == MINI_SHELL)
846 guchar *line;
848 line = mini_contents(filer_window);
849 if (line)
850 add_to_history(line);
853 minibuffer_hide(filer_window);
854 return TRUE;
857 switch (filer_window->mini_type)
859 case MINI_PATH:
860 switch (event->keyval)
862 case GDK_Up:
863 search_in_dir(filer_window, -1);
864 break;
865 case GDK_Down:
866 search_in_dir(filer_window, 1);
867 break;
868 case GDK_Return:
869 case GDK_KP_Enter:
870 path_return_pressed(filer_window,
871 event);
872 break;
873 case GDK_Tab:
874 complete(filer_window);
875 break;
876 default:
877 return FALSE;
879 break;
881 case MINI_SHELL:
882 switch (event->keyval)
884 case GDK_Up:
885 shell_recall(filer_window, 1);
886 break;
887 case GDK_Down:
888 shell_recall(filer_window, -1);
889 break;
890 case GDK_Tab:
891 shell_tab(filer_window);
892 break;
893 case GDK_Return:
894 case GDK_KP_Enter:
895 shell_return_pressed(filer_window);
896 break;
897 default:
898 return FALSE;
900 break;
901 case MINI_SELECT_IF:
902 switch (event->keyval)
904 case GDK_Up:
905 shell_recall(filer_window, 1);
906 break;
907 case GDK_Down:
908 shell_recall(filer_window, -1);
909 break;
910 case GDK_Tab:
911 break;
912 case GDK_Return:
913 case GDK_KP_Enter:
914 select_return_pressed(filer_window,
915 event->time);
916 break;
917 default:
918 return FALSE;
920 break;
921 default:
922 break;
925 #ifndef GTK2
926 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
927 #endif
928 return TRUE;
931 static void changed(GtkEditable *mini, FilerWindow *filer_window)
933 switch (filer_window->mini_type)
935 case MINI_PATH:
936 gtk_idle_add(path_changed, filer_window);
937 return;
938 case MINI_SELECT_IF:
939 set_find_string_colour(GTK_WIDGET(mini),
940 gtk_entry_get_text(
941 GTK_ENTRY(filer_window->minibuffer)));
942 return;
943 default:
944 break;
948 /* Returns a string (which must NOT be freed), or NULL if the buffer
949 * is blank (whitespace only).
951 static guchar *mini_contents(FilerWindow *filer_window)
953 guchar *entry, *c;
955 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
957 for (c = entry; *c; c++)
958 if (!isspace(*c))
959 return entry;
961 return NULL;