r339: The menu key bindings are now only saved if they actually changed.
[rox-filer.git] / ROX-Filer / src / minibuffer.c
blob53206afec5b74bbfed98dca851d2fc366237727b
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
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 "collection.h"
38 #include "find.h"
39 #include "gui_support.h"
40 #include "support.h"
41 #include "minibuffer.h"
42 #include "filer.h"
43 #include "main.h"
44 #include "action.h"
45 #include "dir.h"
46 #include "type.h"
48 static GList *shell_history = NULL;
50 /* Static prototypes */
51 static gint key_press_event(GtkWidget *widget,
52 GdkEventKey *event,
53 FilerWindow *filer_window);
54 static void changed(GtkEditable *mini, FilerWindow *filer_window);
55 static gboolean find_next_match(FilerWindow *filer_window,
56 char *pattern,
57 int dir);
58 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern);
59 static gboolean matches(Collection *collection, int item, char *pattern);
60 static void search_in_dir(FilerWindow *filer_window, int dir);
61 static guchar *mini_contents(FilerWindow *filer_window);
62 static void show_help(FilerWindow *filer_window);
65 /****************************************************************
66 * EXTERNAL INTERFACE *
67 ****************************************************************/
70 /* Creates the minibuffer widgets, setting the appropriate fields
71 * in filer_window.
73 void create_minibuffer(FilerWindow *filer_window)
75 GtkWidget *hbox, *label, *mini;
77 hbox = gtk_hbox_new(FALSE, 0);
79 gtk_box_pack_start(GTK_BOX(hbox),
80 new_help_button((HelpFunc) show_help, filer_window),
81 FALSE, TRUE, 0);
83 label = gtk_label_new("");
84 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 2);
86 mini = gtk_entry_new();
87 gtk_box_pack_start(GTK_BOX(hbox), mini, TRUE, TRUE, 0);
88 gtk_widget_set_style(mini, fixed_style);
89 gtk_signal_connect(GTK_OBJECT(mini), "key_press_event",
90 GTK_SIGNAL_FUNC(key_press_event), filer_window);
91 gtk_signal_connect(GTK_OBJECT(mini), "changed",
92 GTK_SIGNAL_FUNC(changed), filer_window);
94 filer_window->minibuffer = mini;
95 filer_window->minibuffer_label = label;
96 filer_window->minibuffer_area = hbox;
99 void minibuffer_show(FilerWindow *filer_window, MiniType mini_type)
101 Collection *collection;
102 GtkEntry *mini;
104 g_return_if_fail(filer_window != NULL);
105 g_return_if_fail(filer_window->minibuffer != NULL);
107 mini = GTK_ENTRY(filer_window->minibuffer);
109 filer_window->mini_type = MINI_NONE;
110 gtk_label_set_text(GTK_LABEL(filer_window->minibuffer_label),
111 mini_type == MINI_PATH ? _("Goto:") :
112 mini_type == MINI_SHELL ? _("Shell:") :
113 mini_type == MINI_RUN_ACTION ? _("Run Action:") :
114 mini_type == MINI_SELECT_IF ? _("Select If:") :
115 "?");
117 collection = filer_window->collection;
118 collection_move_cursor(collection, 0, 0); /* Turn the cursor on */
119 switch (mini_type)
121 case MINI_PATH:
122 filer_window->mini_cursor_base =
123 MAX(collection->cursor_item, 0);
124 gtk_entry_set_text(mini,
125 make_path(filer_window->path, "")->str);
126 if (filer_window->temp_show_hidden)
128 display_set_hidden(filer_window, FALSE);
129 filer_window->temp_show_hidden = FALSE;
131 break;
132 case MINI_SHELL:
133 case MINI_RUN_ACTION:
134 case MINI_SELECT_IF:
135 filer_window->mini_cursor_base = -1; /* History */
136 gtk_entry_set_text(mini, "");
137 break;
138 default:
139 g_warning("Bad minibuffer type\n");
140 return;
143 filer_window->mini_type = mini_type;
145 gtk_entry_set_position(mini, -1);
147 gtk_widget_show_all(filer_window->minibuffer_area);
149 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
150 filer_window->minibuffer);
153 void minibuffer_hide(FilerWindow *filer_window)
155 filer_window->mini_type = MINI_NONE;
157 gtk_widget_hide(filer_window->minibuffer_area);
158 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
159 GTK_WIDGET(filer_window->collection));
161 if (filer_window->temp_show_hidden)
163 display_set_hidden(filer_window, FALSE);
164 filer_window->temp_show_hidden = FALSE;
168 /* Insert this leafname at the cursor (replacing the selection, if any).
169 * Must be in SHELL or RUN_ACTION mode.
171 void minibuffer_add(FilerWindow *filer_window, guchar *leafname)
173 guchar *esc;
174 GtkEditable *edit = GTK_EDITABLE(filer_window->minibuffer);
175 GtkEntry *entry = GTK_ENTRY(edit);
176 int pos;
178 g_return_if_fail(filer_window->mini_type == MINI_SHELL ||
179 filer_window->mini_type == MINI_RUN_ACTION);
181 esc = shell_escape(leafname);
183 gtk_editable_delete_selection(edit);
184 pos = gtk_editable_get_position(edit);
186 if (pos > 0 && gtk_entry_get_text(entry)[pos - 1] != ' ')
187 gtk_editable_insert_text(edit, " ", 1, &pos);
189 gtk_editable_insert_text(edit, esc, strlen(esc), &pos);
190 gtk_editable_set_position(edit, pos);
192 g_free(esc);
196 /****************************************************************
197 * INTERNAL FUNCTIONS *
198 ****************************************************************/
200 static void show_help(FilerWindow *filer_window)
202 guchar *message;
204 gtk_widget_grab_focus(filer_window->minibuffer);
206 switch (filer_window->mini_type)
208 case MINI_PATH:
209 message = _("Enter the name of a file and I'll display "
210 "it for you. Press Tab to fill in the longest "
211 "match. Escape to close the minibuffer.");
212 break;
213 case MINI_SHELL:
214 message = _("Enter a shell command to execute. Click "
215 "on a file to add it to the buffer.");
216 break;
217 case MINI_RUN_ACTION:
218 message =
219 _("To set the run action for a file, either:\n"
220 "- Drag a file to an application directory (eg drag an image to the "
221 "Gimp), or\n" "- Enter a shell command which contains a \"$1\""
222 "where the name of the file should go (eg ` gimp \"$1\" ')");
223 break;
224 case MINI_SELECT_IF:
225 show_condition_help(NULL);
226 return;
227 default:
228 message = "?!?";
229 break;
232 delayed_error(PROJECT, message);
236 /* PATH ENTRY */
238 static void path_return_pressed(FilerWindow *filer_window, GdkEventKey *event)
240 Collection *collection = filer_window->collection;
241 int item = collection->cursor_item;
242 char *path, *pattern;
243 int flags = OPEN_FROM_MINI | OPEN_SAME_WINDOW;
245 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
246 pattern = strrchr(path, '/');
247 if (pattern)
248 pattern++;
249 else
250 pattern = path;
252 if (item == -1 || item >= collection->number_of_items ||
253 !matches(collection, item, pattern))
255 gdk_beep();
256 return;
259 if ((event->state & GDK_SHIFT_MASK) != 0)
260 flags |= OPEN_SHIFT;
262 filer_openitem(filer_window, item, flags);
265 /* Use the cursor item to fill in the minibuffer.
266 * If there are multiple matches the fill in as much as possible and beep.
268 static void complete(FilerWindow *filer_window)
270 GtkEntry *entry;
271 Collection *collection = filer_window->collection;
272 int cursor = collection->cursor_item;
273 DirItem *item;
274 int shortest_stem = -1;
275 int current_stem;
276 int other;
277 guchar *text, *leaf;
279 if (cursor < 0 || cursor >= collection->number_of_items)
281 gdk_beep();
282 return;
285 entry = GTK_ENTRY(filer_window->minibuffer);
287 item = (DirItem *) collection->items[cursor].data;
289 text = gtk_entry_get_text(entry);
290 leaf = strrchr(text, '/');
291 if (!leaf)
293 gdk_beep();
294 return;
297 leaf++;
298 if (!matches(collection, cursor, leaf))
300 gdk_beep();
301 return;
304 current_stem = strlen(leaf);
306 /* Find the longest other match of this name. It it's longer than
307 * the currently entered text then complete only up to that length.
309 for (other = 0; other < collection->number_of_items; other++)
311 DirItem *other_item = (DirItem *) collection->items[other].data;
312 int stem = 0;
314 if (other == cursor)
315 continue;
317 while (other_item->leafname[stem] && item->leafname[stem])
319 if (other_item->leafname[stem] != item->leafname[stem])
320 break;
321 stem++;
324 /* stem is the index of the first difference */
325 if (stem >= current_stem &&
326 (shortest_stem == -1 || stem < shortest_stem))
327 shortest_stem = stem;
330 if (current_stem == shortest_stem)
331 gdk_beep();
332 else if (current_stem < shortest_stem)
334 guchar *extra;
336 extra = g_strndup(item->leafname + current_stem,
337 shortest_stem - current_stem);
338 gtk_entry_append_text(entry, extra);
339 g_free(extra);
340 gdk_beep();
342 else
344 GString *new;
346 new = make_path(filer_window->path, item->leafname);
348 if (item->base_type == TYPE_DIRECTORY &&
349 (item->flags & ITEM_FLAG_APPDIR) == 0)
350 g_string_append_c(new, '/');
352 gtk_entry_set_text(entry, new->str);
356 static void path_changed(GtkEditable *mini, FilerWindow *filer_window)
358 char *new, *slash;
359 char *path, *real;
361 new = gtk_entry_get_text(GTK_ENTRY(mini));
362 if (*new == '/')
363 new = g_strdup(new);
364 else
365 new = g_strdup_printf("/%s", new);
367 slash = strrchr(new, '/');
368 *slash = '\0';
370 if (*new == '\0')
371 path = "/";
372 else
373 path = new;
375 real = pathdup(path);
377 if (strcmp(real, filer_window->path) != 0)
379 struct stat info;
380 if (mc_stat(real, &info) == 0 && S_ISDIR(info.st_mode))
381 filer_change_to(filer_window, real, slash + 1);
382 else
383 gdk_beep();
385 else
387 if (slash[1] == '.')
389 if (!filer_window->show_hidden)
391 filer_window->temp_show_hidden = TRUE;
392 display_set_hidden(filer_window, TRUE);
395 else if (filer_window->temp_show_hidden)
397 display_set_hidden(filer_window, FALSE);
398 filer_window->temp_show_hidden = FALSE;
401 if (find_exact_match(filer_window, slash + 1) == FALSE &&
402 find_next_match(filer_window, slash + 1, 0) == FALSE)
403 gdk_beep();
406 g_free(real);
407 g_free(new);
410 /* Look for an exact match, and move the cursor to it if found.
411 * TRUE on success.
413 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern)
415 Collection *collection = filer_window->collection;
416 int i;
418 for (i = 0; i < collection->number_of_items; i++)
420 DirItem *item = (DirItem *) collection->items[i].data;
422 if (strcmp(item->leafname, pattern) == 0)
424 collection_set_cursor_item(collection, i);
425 return TRUE;
429 return FALSE;
432 /* Find the next item in the collection that matches 'pattern'. Start from
433 * mini_cursor_base and loop at either end. dir is 1 for a forward search,
434 * -1 for backwards. 0 means forwards, but may stay the same.
436 * Does not automatically update mini_cursor_base.
438 * Returns TRUE if a match is found.
440 static gboolean find_next_match(FilerWindow *filer_window,
441 char *pattern,
442 int dir)
444 Collection *collection = filer_window->collection;
445 int base = filer_window->mini_cursor_base;
446 int item = base;
447 gboolean retval = TRUE;
449 if (collection->number_of_items < 1)
450 return FALSE;
452 if (base < 0 || base>= collection->number_of_items)
453 filer_window->mini_cursor_base = base = 0;
457 /* Step to the next item */
458 item += dir;
460 if (item >= collection->number_of_items)
461 item = 0;
462 else if (item < 0)
463 item = collection->number_of_items - 1;
465 if (dir == 0)
466 dir = 1;
467 else if (item == base)
469 retval = FALSE;
470 break; /* No (other) matches at all */
472 } while (!matches(collection, item, pattern));
474 collection_set_cursor_item(collection, item);
476 return retval;
479 static gboolean matches(Collection *collection, int item_number, char *pattern)
481 DirItem *item = (DirItem *) collection->items[item_number].data;
483 return strncmp(item->leafname, pattern, strlen(pattern)) == 0;
486 /* Find next match and set base for future matches. */
487 static void search_in_dir(FilerWindow *filer_window, int dir)
489 char *path, *pattern;
491 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
492 pattern = strrchr(path, '/');
493 if (pattern)
494 pattern++;
495 else
496 pattern = path;
498 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
499 find_next_match(filer_window, pattern, dir);
500 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
503 /* SHELL COMMANDS */
505 static void add_to_history(guchar *line)
507 guchar *last;
509 last = shell_history ? (guchar *) shell_history->data : NULL;
511 if (last && strcmp(last, line) == 0)
512 return; /* Duplicating last entry */
514 shell_history = g_list_prepend(shell_history, g_strdup(line));
517 static void shell_done(FilerWindow *filer_window)
519 if (filer_exists(filer_window))
520 filer_update_dir(filer_window, TRUE);
523 /* Given a list of matches, return the longest stem. g_free() the result.
524 * Special chars are escaped. If there is only a single (non-dir) match
525 * then a trailing space is added.
527 static guchar *best_match(FilerWindow *filer_window, glob_t *matches)
529 gchar *first = matches->gl_pathv[0];
530 int i;
531 int longest, path_len;
532 guchar *path, *tmp;
534 longest = strlen(first);
536 for (i = 1; i < matches->gl_pathc; i++)
538 int j;
539 guchar *m = matches->gl_pathv[i];
541 for (j = 0; j < longest; j++)
542 if (m[j] != first[j])
543 longest = j;
546 path_len = strlen(filer_window->path);
547 if (strncmp(filer_window->path, first, path_len) == 0 &&
548 first[path_len] == '/' && first[path_len + 1])
550 path = g_strndup(first + path_len + 1, longest - path_len - 1);
552 else
553 path = g_strndup(first, longest);
555 tmp = shell_escape(path);
556 g_free(path);
558 if (matches->gl_pathc == 1 && tmp[strlen(tmp) - 1] != '/')
560 path = g_strdup_printf("%s ", tmp);
561 g_free(tmp);
562 return path;
565 return tmp;
568 static void shell_tab(FilerWindow *filer_window)
570 int i;
571 guchar *entry;
572 guchar quote;
573 int pos;
574 GString *leaf;
575 glob_t matches;
576 int leaf_start;
578 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
579 pos = gtk_editable_get_position(GTK_EDITABLE(filer_window->minibuffer));
580 leaf = g_string_new(NULL);
582 quote = '\0';
583 for (i = 0; i < pos; i++)
585 guchar c = entry[i];
587 if (leaf->len == 0)
588 leaf_start = i;
590 if (c == ' ')
592 g_string_truncate(leaf, 0);
593 continue;
595 else if (c == '\\' && i + 1 < pos)
596 c = entry[++i];
597 else if (c == '"' || c == '\'')
599 guchar cc;
601 for (++i; i < pos; i++)
603 cc = entry[i];
605 if (cc == '\\' && i + 1 < pos)
606 cc = entry[++i];
607 else if (entry[i] == c)
608 break;
609 g_string_append_c(leaf, entry[i]);
611 continue;
614 g_string_append_c(leaf, c);
617 if (leaf->len == 0)
618 leaf_start = pos;
620 if (leaf->str[0] != '/' && leaf->str[0] != '~')
622 g_string_prepend_c(leaf, '/');
623 g_string_prepend(leaf, filer_window->path);
626 g_string_append_c(leaf, '*');
628 if (glob(leaf->str,
629 #ifdef GLOB_TILDE
630 GLOB_TILDE |
631 #endif
632 GLOB_MARK, NULL, &matches) == 0)
634 if (matches.gl_pathc > 0)
636 guchar *best;
637 GtkEditable *edit =
638 GTK_EDITABLE(filer_window->minibuffer);
640 best = best_match(filer_window, &matches);
642 gtk_editable_delete_text(edit, leaf_start, pos);
643 gtk_editable_insert_text(edit, best, strlen(best),
644 &leaf_start);
645 gtk_editable_set_position(edit, leaf_start);
647 g_free(best);
649 if (matches.gl_pathc != 1)
650 gdk_beep();
652 globfree(&matches);
655 g_string_free(leaf, TRUE);
658 /* This is called from shell_return_pressed() so that the command is already
659 * in the history. Returns TRUE if the buffer should be closed.
661 gboolean set_run_action(FilerWindow *filer_window, guchar *command)
663 Collection *collection = filer_window->collection;
664 int n = collection->cursor_item;
665 DirItem *item;
666 guchar *path, *tmp;
667 FILE *file;
668 int error = 0, len;
670 if (!strchr(command, '$'))
672 show_help(filer_window);
673 return FALSE;
676 if (n < 0 || n >= collection->number_of_items)
678 delayed_error(PROJECT,
679 _("You must have the cursor on the item to use for '$1'."));
680 return FALSE;
683 item = (DirItem *) collection->items[n].data;
684 path = type_ask_which_action(item->mime_type->media_type,
685 item->mime_type->subtype);
687 if (!path)
688 return TRUE;
690 tmp = g_strdup_printf("#! /bin/sh\nexec %s\n", command);
691 len = strlen(tmp);
693 file = fopen(path, "wb");
694 if (fwrite(tmp, 1, len, file) < len)
695 error = errno;
696 if (fclose(file) && error == 0)
697 error = errno;
698 if (chmod(path, 0777))
699 error = errno;
701 if (error)
702 report_error(PROJECT, g_strerror(errno));
704 g_free(tmp);
706 return TRUE;
709 /* Either execute the command or make it the default run action */
710 static void shell_return_pressed(FilerWindow *filer_window)
712 GPtrArray *argv;
713 int i;
714 guchar *entry;
715 Collection *collection = filer_window->collection;
716 int child;
718 entry = mini_contents(filer_window);
720 if (!entry)
721 goto out;
723 add_to_history(entry);
725 if (filer_window->mini_type == MINI_RUN_ACTION)
727 if (set_run_action(filer_window, entry))
728 goto out;
729 else
730 return;
733 argv = g_ptr_array_new();
734 g_ptr_array_add(argv, "sh");
735 g_ptr_array_add(argv, "-c");
736 g_ptr_array_add(argv, entry);
737 g_ptr_array_add(argv, "sh");
739 for (i = 0; i < collection->number_of_items; i++)
741 DirItem *item = (DirItem *) collection->items[i].data;
742 if (collection->items[i].selected)
743 g_ptr_array_add(argv, item->leafname);
746 g_ptr_array_add(argv, NULL);
748 child = fork();
750 switch (child)
752 case -1:
753 delayed_error(PROJECT, _("Failed to create "
754 "child process"));
755 break;
756 case 0: /* Child */
757 dup2(to_error_log, STDOUT_FILENO);
758 close_on_exec(STDOUT_FILENO, FALSE);
759 dup2(to_error_log, STDERR_FILENO);
760 close_on_exec(STDERR_FILENO, FALSE);
761 if (chdir(filer_window->path))
762 g_printerr("chdir(%s) failed: %s\n",
763 filer_window->path,
764 g_strerror(errno));
765 execvp((char *) argv->pdata[0],
766 (char **) argv->pdata);
767 g_printerr("execvp(%s, ...) failed: %s\n",
768 (char *) argv->pdata[0],
769 g_strerror(errno));
770 _exit(0);
771 default:
772 on_child_death(child,
773 (CallbackFn) shell_done, filer_window);
774 break;
777 g_ptr_array_free(argv, TRUE);
779 out:
780 minibuffer_hide(filer_window);
783 /* Move through the shell history */
784 static void shell_recall(FilerWindow *filer_window, int dir)
786 guchar *command;
787 int pos = filer_window->mini_cursor_base;
789 pos += dir;
790 if (pos >= 0)
792 command = g_list_nth_data(shell_history, pos);
793 if (!command)
794 return;
796 else
797 command = "";
799 if (pos < -1)
800 pos = -1;
801 filer_window->mini_cursor_base = pos;
803 gtk_entry_set_text(GTK_ENTRY(filer_window->minibuffer), command);
806 /* SELECT IF */
808 static void select_return_pressed(FilerWindow *filer_window)
810 FindCondition *cond;
811 int i, n;
812 guchar *entry;
813 Collection *collection = filer_window->collection;
814 FindInfo info;
816 entry = mini_contents(filer_window);
818 if (!entry)
819 goto out;
821 add_to_history(entry);
823 cond = find_compile(entry);
824 if (!cond)
826 delayed_error(PROJECT, "Invalid Find condition");
827 return;
830 info.now = time(NULL);
831 info.prune = FALSE; /* (don't care) */
832 n = collection->number_of_items;
834 /* If an item at the start is selected then we could lose the
835 * primary selection after checking that item and then need to
836 * gain it again at the end. Therefore, if anything is selected
837 * then select the last item until the end of the search.
839 if (collection->number_selected)
840 collection_select_item(collection, n - 1);
842 for (i = 0; i < n; i++)
844 DirItem *item = (DirItem *) collection->items[i].data;
846 info.leaf = item->leafname;
847 info.fullpath = make_path(filer_window->path, info.leaf)->str;
849 if (lstat(info.fullpath, &info.stats) == 0 &&
850 find_test_condition(cond, &info))
851 collection_select_item(collection, i);
852 else
853 collection_unselect_item(collection, i);
856 find_condition_free(cond);
858 out:
859 minibuffer_hide(filer_window);
863 /* EVENT HANDLERS */
865 static gint key_press_event(GtkWidget *widget,
866 GdkEventKey *event,
867 FilerWindow *filer_window)
869 if (event->keyval == GDK_Escape)
871 if (filer_window->mini_type == MINI_SHELL)
873 guchar *line;
875 line = mini_contents(filer_window);
876 if (line)
877 add_to_history(line);
880 minibuffer_hide(filer_window);
881 return TRUE;
884 switch (filer_window->mini_type)
886 case MINI_PATH:
887 switch (event->keyval)
889 case GDK_Up:
890 search_in_dir(filer_window, -1);
891 break;
892 case GDK_Down:
893 search_in_dir(filer_window, 1);
894 break;
895 case GDK_Return:
896 path_return_pressed(filer_window,
897 event);
898 break;
899 case GDK_Tab:
900 complete(filer_window);
901 break;
902 default:
903 return FALSE;
905 break;
907 case MINI_SHELL:
908 case MINI_RUN_ACTION:
909 switch (event->keyval)
911 case GDK_Up:
912 shell_recall(filer_window, 1);
913 break;
914 case GDK_Down:
915 shell_recall(filer_window, -1);
916 break;
917 case GDK_Tab:
918 shell_tab(filer_window);
919 break;
920 case GDK_Return:
921 shell_return_pressed(filer_window);
922 break;
923 default:
924 return FALSE;
926 break;
927 case MINI_SELECT_IF:
928 switch (event->keyval)
930 case GDK_Up:
931 shell_recall(filer_window, 1);
932 break;
933 case GDK_Down:
934 shell_recall(filer_window, -1);
935 break;
936 case GDK_Tab:
937 break;
938 case GDK_Return:
939 select_return_pressed(filer_window);
940 break;
941 default:
942 return FALSE;
944 break;
945 default:
946 break;
949 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
950 return TRUE;
953 static void changed(GtkEditable *mini, FilerWindow *filer_window)
955 switch (filer_window->mini_type)
957 case MINI_PATH:
958 path_changed(mini, filer_window);
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;