r328: Changed the install script so that the CVS directories don't get installed.
[rox-filer.git] / ROX-Filer / src / minibuffer.c
blob4d4ad399305657beeb1a5a469625f08513fbe258
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
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 "collection.h"
36 #include "find.h"
37 #include "gui_support.h"
38 #include "support.h"
39 #include "minibuffer.h"
40 #include "filer.h"
41 #include "main.h"
42 #include "action.h"
44 static GList *shell_history = NULL;
46 /* Static prototypes */
47 static gint key_press_event(GtkWidget *widget,
48 GdkEventKey *event,
49 FilerWindow *filer_window);
50 static void changed(GtkEditable *mini, FilerWindow *filer_window);
51 static void find_next_match(FilerWindow *filer_window, char *pattern, int dir);
52 static gboolean matches(Collection *collection, int item, char *pattern);
53 static void search_in_dir(FilerWindow *filer_window, int dir);
54 static guchar *mini_contents(FilerWindow *filer_window);
55 static void show_help(FilerWindow *filer_window);
58 /****************************************************************
59 * EXTERNAL INTERFACE *
60 ****************************************************************/
63 /* Creates the minibuffer widgets, setting the appropriate fields
64 * in filer_window.
66 void create_minibuffer(FilerWindow *filer_window)
68 GtkWidget *hbox, *label, *mini;
70 hbox = gtk_hbox_new(FALSE, 0);
72 gtk_box_pack_start(GTK_BOX(hbox),
73 new_help_button((HelpFunc) show_help, filer_window),
74 FALSE, TRUE, 0);
76 label = gtk_label_new("");
77 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 2);
79 mini = gtk_entry_new();
80 gtk_box_pack_start(GTK_BOX(hbox), mini, TRUE, TRUE, 0);
81 gtk_widget_set_style(mini, fixed_style);
82 gtk_signal_connect(GTK_OBJECT(mini), "key_press_event",
83 GTK_SIGNAL_FUNC(key_press_event), filer_window);
84 gtk_signal_connect(GTK_OBJECT(mini), "changed",
85 GTK_SIGNAL_FUNC(changed), filer_window);
87 filer_window->minibuffer = mini;
88 filer_window->minibuffer_label = label;
89 filer_window->minibuffer_area = hbox;
92 void minibuffer_show(FilerWindow *filer_window, MiniType mini_type)
94 Collection *collection;
95 GtkEntry *mini;
97 g_return_if_fail(filer_window != NULL);
98 g_return_if_fail(filer_window->minibuffer != NULL);
100 mini = GTK_ENTRY(filer_window->minibuffer);
102 filer_window->mini_type = MINI_NONE;
103 gtk_label_set_text(GTK_LABEL(filer_window->minibuffer_label),
104 mini_type == MINI_PATH ? _("Goto:") :
105 mini_type == MINI_SHELL ? _("Shell:") :
106 mini_type == MINI_RUN_ACTION ? _("Run Action:") :
107 mini_type == MINI_SELECT_IF ? _("Select If:") :
108 "?");
110 collection = filer_window->collection;
111 collection_move_cursor(collection, 0, 0); /* Turn the cursor on */
112 switch (mini_type)
114 case MINI_PATH:
115 filer_window->mini_cursor_base =
116 MAX(collection->cursor_item, 0);
117 gtk_entry_set_text(mini,
118 make_path(filer_window->path, "")->str);
119 if (filer_window->temp_show_hidden)
121 display_set_hidden(filer_window, FALSE);
122 filer_window->temp_show_hidden = FALSE;
124 break;
125 case MINI_SHELL:
126 case MINI_RUN_ACTION:
127 case MINI_SELECT_IF:
128 filer_window->mini_cursor_base = -1; /* History */
129 gtk_entry_set_text(mini, "");
130 break;
131 default:
132 g_warning("Bad minibuffer type\n");
133 return;
136 filer_window->mini_type = mini_type;
138 gtk_entry_set_position(mini, -1);
140 gtk_widget_show_all(filer_window->minibuffer_area);
142 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
143 filer_window->minibuffer);
146 void minibuffer_hide(FilerWindow *filer_window)
148 filer_window->mini_type = MINI_NONE;
150 gtk_widget_hide(filer_window->minibuffer_area);
151 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
152 GTK_WIDGET(filer_window->collection));
154 if (filer_window->temp_show_hidden)
156 display_set_hidden(filer_window, FALSE);
157 filer_window->temp_show_hidden = FALSE;
161 /* Insert this leafname at the cursor (replacing the selection, if any).
162 * Must be in SHELL or RUN_ACTION mode.
164 void minibuffer_add(FilerWindow *filer_window, guchar *leafname)
166 guchar *esc;
167 GtkEditable *edit = GTK_EDITABLE(filer_window->minibuffer);
168 GtkEntry *entry = GTK_ENTRY(edit);
169 int pos;
171 g_return_if_fail(filer_window->mini_type == MINI_SHELL ||
172 filer_window->mini_type == MINI_RUN_ACTION);
174 esc = shell_escape(leafname);
176 gtk_editable_delete_selection(edit);
177 pos = gtk_editable_get_position(edit);
179 if (pos > 0 && gtk_entry_get_text(entry)[pos - 1] != ' ')
180 gtk_editable_insert_text(edit, " ", 1, &pos);
182 gtk_editable_insert_text(edit, esc, strlen(esc), &pos);
183 gtk_editable_set_position(edit, pos);
185 g_free(esc);
189 /****************************************************************
190 * INTERNAL FUNCTIONS *
191 ****************************************************************/
193 static void show_help(FilerWindow *filer_window)
195 guchar *message;
197 gtk_widget_grab_focus(filer_window->minibuffer);
199 switch (filer_window->mini_type)
201 case MINI_PATH:
202 message = _("Enter the name of a file and I'll display "
203 "it for you. Press Tab to fill in the longest "
204 "match. Escape to close the minibuffer.");
205 break;
206 case MINI_SHELL:
207 message = _("Enter a shell command to execute. Click "
208 "on a file to add it to the buffer.");
209 break;
210 case MINI_RUN_ACTION:
211 message =
212 _("To set the run action for a file, either:\n"
213 "- Drag a file to an application directory (eg drag an image to the "
214 "Gimp), or\n" "- Enter a shell command which contains a \"$1\""
215 "where the name of the file should go (eg ` gimp \"$1\" ')");
216 break;
217 case MINI_SELECT_IF:
218 show_condition_help(NULL);
219 return;
220 default:
221 message = "?!?";
222 break;
225 delayed_error(PROJECT, message);
229 /* PATH ENTRY */
231 static void path_return_pressed(FilerWindow *filer_window, GdkEventKey *event)
233 Collection *collection = filer_window->collection;
234 int item = collection->cursor_item;
235 char *path, *pattern;
236 int flags = OPEN_FROM_MINI | OPEN_SAME_WINDOW;
238 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
239 pattern = strrchr(path, '/');
240 if (pattern)
241 pattern++;
242 else
243 pattern = path;
245 if (item == -1 || item >= collection->number_of_items ||
246 !matches(collection, item, pattern))
248 gdk_beep();
249 return;
252 if ((event->state & GDK_SHIFT_MASK) != 0)
253 flags |= OPEN_SHIFT;
255 filer_openitem(filer_window, item, flags);
258 /* Use the cursor item to fill in the minibuffer.
259 * If there are multiple matches the fill in as much as possible and beep.
261 static void complete(FilerWindow *filer_window)
263 GtkEntry *entry;
264 Collection *collection = filer_window->collection;
265 int cursor = collection->cursor_item;
266 DirItem *item;
267 int shortest_stem = -1;
268 int current_stem;
269 int other;
270 guchar *text, *leaf;
272 if (cursor < 0 || cursor >= collection->number_of_items)
274 gdk_beep();
275 return;
278 entry = GTK_ENTRY(filer_window->minibuffer);
280 item = (DirItem *) collection->items[cursor].data;
282 text = gtk_entry_get_text(entry);
283 leaf = strrchr(text, '/');
284 if (!leaf)
286 gdk_beep();
287 return;
290 leaf++;
291 if (!matches(collection, cursor, leaf))
293 gdk_beep();
294 return;
297 current_stem = strlen(leaf);
299 /* Find the longest other match of this name. It it's longer than
300 * the currently entered text then complete only up to that length.
302 for (other = 0; other < collection->number_of_items; other++)
304 DirItem *other_item = (DirItem *) collection->items[other].data;
305 int stem = 0;
307 if (other == cursor)
308 continue;
310 while (other_item->leafname[stem] && item->leafname[stem])
312 if (other_item->leafname[stem] != item->leafname[stem])
313 break;
314 stem++;
317 /* stem is the index of the first difference */
318 if (stem >= current_stem &&
319 (shortest_stem == -1 || stem < shortest_stem))
320 shortest_stem = stem;
323 if (current_stem == shortest_stem)
324 gdk_beep();
325 else if (current_stem < shortest_stem)
327 guchar *extra;
329 extra = g_strndup(item->leafname + current_stem,
330 shortest_stem - current_stem);
331 gtk_entry_append_text(entry, extra);
332 g_free(extra);
333 gdk_beep();
335 else
337 GString *new;
339 new = make_path(filer_window->path, item->leafname);
341 if (item->base_type == TYPE_DIRECTORY &&
342 (item->flags & ITEM_FLAG_APPDIR) == 0)
343 g_string_append_c(new, '/');
345 gtk_entry_set_text(entry, new->str);
349 static void path_changed(GtkEditable *mini, FilerWindow *filer_window)
351 char *new, *slash;
352 char *path, *real;
354 new = gtk_entry_get_text(GTK_ENTRY(mini));
355 if (*new == '/')
356 new = g_strdup(new);
357 else
358 new = g_strdup_printf("/%s", new);
360 slash = strrchr(new, '/');
361 *slash = '\0';
363 if (*new == '\0')
364 path = "/";
365 else
366 path = new;
368 real = pathdup(path);
370 if (strcmp(real, filer_window->path) != 0)
372 struct stat info;
373 if (mc_stat(real, &info) == 0 && S_ISDIR(info.st_mode))
374 filer_change_to(filer_window, real, slash + 1);
375 else
376 gdk_beep();
378 else
380 Collection *collection = filer_window->collection;
381 int item;
383 if (slash[1] == '.')
385 if (!filer_window->show_hidden)
387 filer_window->temp_show_hidden = TRUE;
388 display_set_hidden(filer_window, TRUE);
391 else if (filer_window->temp_show_hidden)
393 display_set_hidden(filer_window, FALSE);
394 filer_window->temp_show_hidden = FALSE;
397 find_next_match(filer_window, slash + 1, 0);
398 item = collection->cursor_item;
399 if (item != -1 && !matches(collection, item, slash + 1))
400 gdk_beep();
403 g_free(real);
404 g_free(new);
407 /* Find the next item in the collection that matches 'pattern'. Start from
408 * mini_cursor_base and loop at either end. dir is 1 for a forward search,
409 * -1 for backwards. 0 means forwards, but may stay the same.
411 * Does not automatically update mini_cursor_base.
413 static void find_next_match(FilerWindow *filer_window, char *pattern, int dir)
415 Collection *collection = filer_window->collection;
416 int base = filer_window->mini_cursor_base;
417 int item = base;
419 if (collection->number_of_items < 1)
420 return;
422 if (base < 0 || base>= collection->number_of_items)
423 filer_window->mini_cursor_base = base = 0;
427 /* Step to the next item */
428 item += dir;
430 if (item >= collection->number_of_items)
431 item = 0;
432 else if (item < 0)
433 item = collection->number_of_items - 1;
435 if (dir == 0)
436 dir = 1;
437 else if (item == base)
438 break; /* No (other) matches at all */
441 } while (!matches(collection, item, pattern));
443 collection_set_cursor_item(collection, item);
446 static gboolean matches(Collection *collection, int item_number, char *pattern)
448 DirItem *item = (DirItem *) collection->items[item_number].data;
450 return strncmp(item->leafname, pattern, strlen(pattern)) == 0;
453 /* Find next match and set base for future matches. */
454 static void search_in_dir(FilerWindow *filer_window, int dir)
456 char *path, *pattern;
458 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
459 pattern = strrchr(path, '/');
460 if (pattern)
461 pattern++;
462 else
463 pattern = path;
465 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
466 find_next_match(filer_window, pattern, dir);
467 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
470 /* SHELL COMMANDS */
472 static void add_to_history(guchar *line)
474 guchar *last;
476 last = shell_history ? (guchar *) shell_history->data : NULL;
478 if (last && strcmp(last, line) == 0)
479 return; /* Duplicating last entry */
481 shell_history = g_list_prepend(shell_history, g_strdup(line));
484 static void shell_done(FilerWindow *filer_window)
486 if (filer_exists(filer_window))
487 filer_update_dir(filer_window, TRUE);
490 /* Given a list of matches, return the longest stem. g_free() the result.
491 * Special chars are escaped. If there is only a single (non-dir) match
492 * then a trailing space is added.
494 static guchar *best_match(FilerWindow *filer_window, glob_t *matches)
496 gchar *first = matches->gl_pathv[0];
497 int i;
498 int longest, path_len;
499 guchar *path, *tmp;
501 longest = strlen(first);
503 for (i = 1; i < matches->gl_pathc; i++)
505 int j;
506 guchar *m = matches->gl_pathv[i];
508 for (j = 0; j < longest; j++)
509 if (m[j] != first[j])
510 longest = j;
513 path_len = strlen(filer_window->path);
514 if (strncmp(filer_window->path, first, path_len) == 0 &&
515 first[path_len] == '/' && first[path_len + 1])
517 path = g_strndup(first + path_len + 1, longest - path_len - 1);
519 else
520 path = g_strndup(first, longest);
522 tmp = shell_escape(path);
523 g_free(path);
525 if (matches->gl_pathc == 1 && tmp[strlen(tmp) - 1] != '/')
527 path = g_strdup_printf("%s ", tmp);
528 g_free(tmp);
529 return path;
532 return tmp;
535 static void shell_tab(FilerWindow *filer_window)
537 int i;
538 guchar *entry;
539 guchar quote;
540 int pos;
541 GString *leaf;
542 glob_t matches;
543 int leaf_start;
545 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
546 pos = gtk_editable_get_position(GTK_EDITABLE(filer_window->minibuffer));
547 leaf = g_string_new(NULL);
549 quote = '\0';
550 for (i = 0; i < pos; i++)
552 guchar c = entry[i];
554 if (leaf->len == 0)
555 leaf_start = i;
557 if (c == ' ')
559 g_string_truncate(leaf, 0);
560 continue;
562 else if (c == '\\' && i + 1 < pos)
563 c = entry[++i];
564 else if (c == '"' || c == '\'')
566 guchar cc;
568 for (++i; i < pos; i++)
570 cc = entry[i];
572 if (cc == '\\' && i + 1 < pos)
573 cc = entry[++i];
574 else if (entry[i] == c)
575 break;
576 g_string_append_c(leaf, entry[i]);
578 continue;
581 g_string_append_c(leaf, c);
584 if (leaf->len == 0)
585 leaf_start = pos;
587 if (leaf->str[0] != '/' && leaf->str[0] != '~')
589 g_string_prepend_c(leaf, '/');
590 g_string_prepend(leaf, filer_window->path);
593 g_string_append_c(leaf, '*');
595 if (glob(leaf->str,
596 #ifdef GLOB_TILDE
597 GLOB_TILDE |
598 #endif
599 GLOB_MARK, NULL, &matches) == 0)
601 if (matches.gl_pathc > 0)
603 guchar *best;
604 GtkEditable *edit =
605 GTK_EDITABLE(filer_window->minibuffer);
607 best = best_match(filer_window, &matches);
609 gtk_editable_delete_text(edit, leaf_start, pos);
610 gtk_editable_insert_text(edit, best, strlen(best),
611 &leaf_start);
612 gtk_editable_set_position(edit, leaf_start);
614 g_free(best);
616 if (matches.gl_pathc != 1)
617 gdk_beep();
619 globfree(&matches);
622 g_string_free(leaf, TRUE);
625 /* This is called from shell_return_pressed() so that the command is already
626 * in the history. Returns TRUE if the buffer should be closed.
628 gboolean set_run_action(FilerWindow *filer_window, guchar *command)
630 Collection *collection = filer_window->collection;
631 int n = collection->cursor_item;
632 DirItem *item;
633 guchar *path, *tmp;
634 FILE *file;
635 int error = 0, len;
637 if (!strchr(command, '$'))
639 show_help(filer_window);
640 return FALSE;
643 if (n < 0 || n >= collection->number_of_items)
645 delayed_error(PROJECT,
646 _("You must have the cursor on the item to use for '$1'."));
647 return FALSE;
650 item = (DirItem *) collection->items[n].data;
651 path = type_ask_which_action(item->mime_type->media_type,
652 item->mime_type->subtype);
654 if (!path)
655 return TRUE;
657 tmp = g_strdup_printf("#! /bin/sh\nexec %s\n", command);
658 len = strlen(tmp);
660 file = fopen(path, "wb");
661 if (fwrite(tmp, 1, len, file) < len)
662 error = errno;
663 if (fclose(file) && error == 0)
664 error = errno;
665 if (chmod(path, 0777))
666 error = errno;
668 if (error)
669 report_error(PROJECT, g_strerror(errno));
671 g_free(tmp);
673 return TRUE;
676 /* Either execute the command or make it the default run action */
677 static void shell_return_pressed(FilerWindow *filer_window)
679 GPtrArray *argv;
680 int i;
681 guchar *entry;
682 Collection *collection = filer_window->collection;
683 int child;
685 entry = mini_contents(filer_window);
687 if (!entry)
688 goto out;
690 add_to_history(entry);
692 if (filer_window->mini_type == MINI_RUN_ACTION)
694 if (set_run_action(filer_window, entry))
695 goto out;
696 else
697 return;
700 argv = g_ptr_array_new();
701 g_ptr_array_add(argv, "sh");
702 g_ptr_array_add(argv, "-c");
703 g_ptr_array_add(argv, entry);
704 g_ptr_array_add(argv, "sh");
706 for (i = 0; i < collection->number_of_items; i++)
708 DirItem *item = (DirItem *) collection->items[i].data;
709 if (collection->items[i].selected)
710 g_ptr_array_add(argv, item->leafname);
713 g_ptr_array_add(argv, NULL);
715 child = fork();
717 switch (child)
719 case -1:
720 delayed_error(PROJECT, _("Failed to create "
721 "child process"));
722 break;
723 case 0: /* Child */
724 dup2(to_error_log, STDOUT_FILENO);
725 close_on_exec(STDOUT_FILENO, FALSE);
726 dup2(to_error_log, STDERR_FILENO);
727 close_on_exec(STDERR_FILENO, FALSE);
728 if (chdir(filer_window->path))
729 g_printerr("chdir(%s) failed: %s\n",
730 filer_window->path,
731 g_strerror(errno));
732 execvp((char *) argv->pdata[0],
733 (char **) argv->pdata);
734 g_printerr("execvp(%s, ...) failed: %s\n",
735 (char *) argv->pdata[0],
736 g_strerror(errno));
737 _exit(0);
738 default:
739 on_child_death(child,
740 (CallbackFn) shell_done, filer_window);
741 break;
744 g_ptr_array_free(argv, TRUE);
746 out:
747 minibuffer_hide(filer_window);
750 /* Move through the shell history */
751 static void shell_recall(FilerWindow *filer_window, int dir)
753 guchar *command;
754 int pos = filer_window->mini_cursor_base;
756 pos += dir;
757 if (pos >= 0)
759 command = g_list_nth_data(shell_history, pos);
760 if (!command)
761 return;
763 else
764 command = "";
766 if (pos < -1)
767 pos = -1;
768 filer_window->mini_cursor_base = pos;
770 gtk_entry_set_text(GTK_ENTRY(filer_window->minibuffer), command);
773 /* SELECT IF */
775 static void select_return_pressed(FilerWindow *filer_window)
777 FindCondition *cond;
778 int i, n;
779 guchar *entry;
780 Collection *collection = filer_window->collection;
781 FindInfo info;
783 entry = mini_contents(filer_window);
785 if (!entry)
786 goto out;
788 add_to_history(entry);
790 cond = find_compile(entry);
791 if (!cond)
793 delayed_error(PROJECT, "Invalid Find condition");
794 return;
797 info.now = time(NULL);
798 info.prune = FALSE; /* (don't care) */
799 n = collection->number_of_items;
801 /* If an item at the start is selected then we could lose the
802 * primary selection after checking that item and then need to
803 * gain it again at the end. Therefore, if anything is selected
804 * then select the last item until the end of the search.
806 if (collection->number_selected)
807 collection_select_item(collection, n - 1);
809 for (i = 0; i < n; i++)
811 DirItem *item = (DirItem *) collection->items[i].data;
813 info.leaf = item->leafname;
814 info.fullpath = make_path(filer_window->path, info.leaf)->str;
816 if (lstat(info.fullpath, &info.stats) == 0 &&
817 find_test_condition(cond, &info))
818 collection_select_item(collection, i);
819 else
820 collection_unselect_item(collection, i);
823 find_condition_free(cond);
825 out:
826 minibuffer_hide(filer_window);
830 /* EVENT HANDLERS */
832 static gint key_press_event(GtkWidget *widget,
833 GdkEventKey *event,
834 FilerWindow *filer_window)
836 if (event->keyval == GDK_Escape)
838 if (filer_window->mini_type == MINI_SHELL)
840 guchar *line;
842 line = mini_contents(filer_window);
843 if (line)
844 add_to_history(line);
847 minibuffer_hide(filer_window);
848 return TRUE;
851 switch (filer_window->mini_type)
853 case MINI_PATH:
854 switch (event->keyval)
856 case GDK_Up:
857 search_in_dir(filer_window, -1);
858 break;
859 case GDK_Down:
860 search_in_dir(filer_window, 1);
861 break;
862 case GDK_Return:
863 path_return_pressed(filer_window,
864 event);
865 break;
866 case GDK_Tab:
867 complete(filer_window);
868 break;
869 default:
870 return FALSE;
872 break;
874 case MINI_SHELL:
875 case MINI_RUN_ACTION:
876 switch (event->keyval)
878 case GDK_Up:
879 shell_recall(filer_window, 1);
880 break;
881 case GDK_Down:
882 shell_recall(filer_window, -1);
883 break;
884 case GDK_Tab:
885 shell_tab(filer_window);
886 break;
887 case GDK_Return:
888 shell_return_pressed(filer_window);
889 break;
890 default:
891 return FALSE;
893 break;
894 case MINI_SELECT_IF:
895 switch (event->keyval)
897 case GDK_Up:
898 shell_recall(filer_window, 1);
899 break;
900 case GDK_Down:
901 shell_recall(filer_window, -1);
902 break;
903 case GDK_Tab:
904 break;
905 case GDK_Return:
906 select_return_pressed(filer_window);
907 break;
908 default:
909 return FALSE;
911 break;
912 default:
913 break;
916 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
917 return TRUE;
920 static void changed(GtkEditable *mini, FilerWindow *filer_window)
922 switch (filer_window->mini_type)
924 case MINI_PATH:
925 path_changed(mini, filer_window);
926 return;
927 default:
928 break;
932 /* Returns a string (which must NOT be freed), or NULL if the buffer
933 * is blank (whitespace only).
935 static guchar *mini_contents(FilerWindow *filer_window)
937 guchar *entry, *c;
939 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
941 for (c = entry; *c; c++)
942 if (!isspace(*c))
943 return entry;
945 return NULL;