1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 static char * back_xpm[] = {
81 static char * up_xpm[] = {
134 static char * forward_xpm[] = {
187 static char * refresh_xpm[] = {
225 #include <sys/types.h>
226 #include <sys/stat.h>
227 #include <sys/param.h>
239 #if (defined TORRIE_DEBUG || defined LEO)
240 #include <gdk/gdkkeysyms.h>
241 #include <gtk/gtkbutton.h>
242 #include <gtk/gtkentry.h>
243 #include "gtkfilesel-linux.h"
244 #include <gtk/gtkhbox.h>
245 #include <gtk/gtkhbbox.h>
246 #include <gtk/gtklabel.h>
247 #include <gtk/gtklist.h>
248 #include <gtk/gtklistitem.h>
249 #include <gtk/gtkmain.h>
250 #include <gtk/gtkscrolledwindow.h>
251 #include <gtk/gtksignal.h>
252 #include <gtk/gtkvbox.h>
253 #include <gtk/gtkmenu.h>
254 #include <gtk/gtkmenuitem.h>
255 #include <gtk/gtkoptionmenu.h>
256 #include <gtk/gtkclist.h>
257 #include <gtk/gtkdialog.h>
258 #include <gtk/gtkcombo.h>
259 #include <gtk/gtkframe.h>
260 #include <gtk/gtkhpaned.h>
261 #include <gtk/gtktable.h>
262 #include <gtk/gtkpixmap.h>
263 #include <gtk/gtknotebook.h>
264 #include <gtk/gtkhseparator.h>
265 #include <gtk/gtktogglebutton.h>
267 #include "gdk/gdkkeysyms.h"
268 #include "gtkbutton.h"
269 #include "gtkentry.h"
270 #include "gtkfilesel.h"
272 #include "gtkhbbox.h"
273 #include "gtklabel.h"
275 #include "gtklistitem.h"
277 #include "gtkscrolledwindow.h"
278 #include "gtksignal.h"
281 #include "gtkmenuitem.h"
282 #include "gtkoptionmenu.h"
283 #include "gtkclist.h"
284 #include "gtkdialog.h"
285 #include "gtkcombo.h"
286 #include "gtkframe.h"
287 #include "gtkhpaned.h"
288 #include "gtktable.h"
289 #include "gtkpixmap.h"
290 #include "gtknotebook.h"
291 #include "gtkhseparator.h"
292 #include "gtktogglebutton.h"
300 #include "forward.xpm"
301 #include "refresh.xpm"
304 #define DIR_LIST_WIDTH 180
305 #define DIR_LIST_HEIGHT 180
306 #define FILE_LIST_WIDTH 180
307 #define FILE_LIST_HEIGHT 180
308 #define BOOKMARK_FILE "/.gtkfilesel_bookmarks"
309 #define MASK_FILE "/.gtkfilesel_masks"
310 #define TIME_STRING_BUF 50
312 /* I've put this here so it doesn't get confused with the
313 * file completion interface */
314 typedef struct _HistoryCallbackArg HistoryCallbackArg;
316 struct _HistoryCallbackArg
319 GtkWidget *menu_item;
323 typedef struct _BookmarkMenuStruct BookmarkMenuStruct;
324 struct _BookmarkMenuStruct {
325 GtkWidget *menu_item;
330 typedef struct _CompletionState CompletionState;
331 typedef struct _CompletionDir CompletionDir;
332 typedef struct _CompletionDirSent CompletionDirSent;
333 typedef struct _CompletionDirEntry CompletionDirEntry;
334 typedef struct _CompletionUserDir CompletionUserDir;
335 typedef struct _PossibleCompletion PossibleCompletion;
337 /* Non-external file completion decls and structures */
339 /* A contant telling PRCS how many directories to cache. Its actually
340 * kept in a list, so the geometry isn't important. */
341 #define CMPL_DIRECTORY_CACHE_SIZE 10
343 /* A constant used to determine whether a substring was an exact
344 * match by first_diff_index()
346 #define PATTERN_MATCH -1
347 /* The arguments used by all fnmatch() calls below
349 #define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD)
351 #define CMPL_ERRNO_TOO_LONG ((1<<16)-1)
353 /* This structure contains all the useful information about a directory
354 * for the purposes of filename completion. These structures are cached
355 * in the CompletionState struct. CompletionDir's are reference counted.
357 struct _CompletionDirSent
364 gchar *name_buffer; /* memory segment containing names of all entries */
366 struct _CompletionDirEntry *entries;
369 struct _CompletionDir
371 CompletionDirSent *sent;
376 struct _CompletionDir *cmpl_parent;
381 /* This structure contains pairs of directory entry names with a flag saying
382 * whether or not they are a valid directory. NOTE: This information is used
383 * to provide the caller with information about whether to update its completions
384 * or try to open a file. Since directories are cached by the directory mtime,
385 * a symlink which points to an invalid file (which will not be a directory),
386 * will not be reevaluated if that file is created, unless the containing
387 * directory is touched. I consider this case to be worth ignoring (josh).
389 struct _CompletionDirEntry
395 struct _CompletionUserDir
401 struct _PossibleCompletion
403 /* accessible fields, all are accessed externally by functions
407 gint is_a_completion;
419 struct _CompletionState
421 gint last_valid_char;
423 gint updated_text_len;
424 gint updated_text_alloc;
427 gchar *user_dir_name_buffer;
428 gint user_directories_len;
430 gchar *last_completion_text;
432 gint user_completion_index; /* if >= 0, currently completing ~user */
434 struct _CompletionDir *completion_dir; /* directory completing from */
435 struct _CompletionDir *active_completion_dir;
437 struct _PossibleCompletion the_completion;
439 struct _CompletionDir *reference_dir; /* initial directory */
441 GList* directory_storage;
442 GList* directory_sent_storage;
444 struct _CompletionUserDir *user_directories;
447 /* Widgets from the Properties Dialog */
448 typedef struct _PropertiesPrivate PropertiesPrivate;
450 struct _PropertiesPrivate
452 GtkWidget *mode_label;
453 GtkWidget *mode_buttons[12];
456 /* pixmap creation function */
457 GtkWidget* create_pixmap (GtkWidget *widget,
458 const gchar *pixmap_char);
460 /* File completion functions which would be external, were they used
461 * outside of this file.
464 static CompletionState* cmpl_init_state (void);
465 static void cmpl_free_state (CompletionState *cmpl_state);
466 static gint cmpl_state_okay (CompletionState* cmpl_state);
467 static gchar* cmpl_strerror (gint);
469 static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete,
470 gchar **remaining_text,
471 CompletionState *cmpl_state);
473 /* Returns a name for consideration, possibly a completion, this name
474 * will be invalid after the next call to cmpl_next_completion.
476 static char* cmpl_this_completion (PossibleCompletion*);
478 /* True if this completion matches the given text. Otherwise, this
479 * output can be used to have a list of non-completions.
481 static gint cmpl_is_a_completion (PossibleCompletion*);
483 /* True if the completion is a directory
485 static gint cmpl_is_directory (PossibleCompletion*);
487 /* Obtains the next completion, or NULL
489 static PossibleCompletion* cmpl_next_completion (CompletionState*);
491 /* Updating completions: the return value of cmpl_updated_text() will
492 * be text_to_complete completed as much as possible after the most
493 * recent call to cmpl_completion_matches. For the present
494 * application, this is the suggested replacement for the user's input
495 * string. You must CALL THIS AFTER ALL cmpl_text_completions have
498 static gchar* cmpl_updated_text (CompletionState* cmpl_state);
500 /* After updating, to see if the completion was a directory, call
501 * this. If it was, you should consider re-calling completion_matches.
503 static gint cmpl_updated_dir (CompletionState* cmpl_state);
505 /* Current location: if using file completion, return the current
506 * directory, from which file completion begins. More specifically,
507 * the cwd concatenated with all exact completions up to the last
508 * directory delimiter('/').
510 static gchar* cmpl_reference_position (CompletionState* cmpl_state);
512 /* backing up: if cmpl_completion_matches returns NULL, you may query
513 * the index of the last completable character into cmpl_updated_text.
515 static gint cmpl_last_valid_char (CompletionState* cmpl_state);
517 /* When the user selects a non-directory, call cmpl_completion_fullname
518 * to get the full name of the selected file.
520 static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state);
523 /* Directory operations. */
524 static CompletionDir* open_ref_dir (gchar* text_to_complete,
525 gchar** remaining_text,
526 CompletionState* cmpl_state);
527 static gboolean check_dir (gchar *dir_name,
529 gboolean *stat_subdirs);
530 static CompletionDir* open_dir (gchar* dir_name,
531 CompletionState* cmpl_state);
532 static CompletionDir* open_user_dir (gchar* text_to_complete,
533 CompletionState *cmpl_state);
534 static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir,
535 CompletionState *cmpl_state);
536 static CompletionDirSent* open_new_dir (gchar* dir_name,
538 gboolean stat_subdirs);
539 static gint correct_dir_fullname (CompletionDir* cmpl_dir);
540 static gint correct_parent (CompletionDir* cmpl_dir,
542 static gchar* find_parent_dir_fullname (gchar* dirname);
543 static CompletionDir* attach_dir (CompletionDirSent* sent,
545 CompletionState *cmpl_state);
546 static void free_dir_sent (CompletionDirSent* sent);
547 static void free_dir (CompletionDir *dir);
548 static void prune_memory_usage(CompletionState *cmpl_state);
550 /* Completion operations */
551 static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete,
552 CompletionState *cmpl_state);
553 static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state);
554 static CompletionDir* find_completion_dir(gchar* text_to_complete,
555 gchar** remaining_text,
556 CompletionState* cmpl_state);
557 static PossibleCompletion* append_completion_text(gchar* text,
558 CompletionState* cmpl_state);
559 static gint get_pwdb(CompletionState* cmpl_state);
560 static gint first_diff_index(gchar* pat, gchar* text);
561 static gint compare_user_dir(const void* a, const void* b);
562 static gint compare_cmpl_dir(const void* a, const void* b);
563 static void update_cmpl(PossibleCompletion* poss,
564 CompletionState* cmpl_state);
566 static void gtk_file_selection_class_init (GtkFileSelectionClass *klass);
567 static void gtk_file_selection_init (GtkFileSelection *filesel);
568 static void gtk_file_selection_realize (GtkWidget *widget);
569 static void gtk_file_selection_destroy (GtkObject *object);
570 static gint gtk_file_selection_key_press (GtkWidget *widget,
574 static void gtk_file_selection_file_button (GtkWidget *widget,
577 GdkEventButton *bevent,
580 static void gtk_file_selection_dir_button (GtkWidget *widget,
583 GdkEventButton *bevent,
586 static void gtk_file_selection_undir_button (GtkWidget *widget,
589 GdkEventButton *bevent,
592 static void gtk_file_selection_populate (GtkFileSelection *fs,
595 static void gtk_file_selection_abort (GtkFileSelection *fs);
597 static void gtk_file_selection_update_history_menu (GtkFileSelection *fs,
600 static void gtk_file_selection_create_dir (gpointer data);
601 static void gtk_file_selection_delete_file (gpointer data);
602 static void gtk_file_selection_rename_file (gpointer data);
603 static void gtk_file_selection_properties (gpointer data);
604 static void gtk_file_selection_properties_update_mode (GtkWidget *widget, gpointer data);
605 static mode_t gtk_file_selection_properties_get_mode (PropertiesPrivate* private);
607 static gboolean gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data);
608 static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget,
611 static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist,
612 GdkEventButton *event,
615 static void gtk_file_selection_bookmark_callback (GtkWidget *widget, gpointer data);
616 static void gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data);
617 static gint gtk_file_selection_mask_entry_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data);
618 static gint gtk_file_selection_mask_entry_button_callback (GtkWidget *widget, GdkEventButton *event, gpointer data);
620 //static void gtk_file_selection_home_button (GtkWidget *widget, gpointer data);
621 static void gtk_file_selection_bookmark_button (GtkWidget *widget,
622 GtkFileSelection *fs);
624 static void gtk_file_selection_up_button (GtkWidget *widget, gpointer data);
625 static void gtk_file_selection_prev_button (GtkWidget *widget, gpointer data);
626 static void gtk_file_selection_next_button (GtkWidget *widget, gpointer data);
627 static void gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data);
629 static gint gtk_file_selection_files_list_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data);
632 static gint gtk_file_selection_match_char (gchar, gchar *mask);
633 static gint gtk_file_selection_match_mask (gchar *,gchar *);
635 static void gtk_file_selection_load_bookmarks(GtkFileSelection *fs);
636 static void gtk_file_selection_add_bookmark (GtkFileSelection *fs, gchar *desc, gchar *path);
637 gint gtk_file_selection_save_bookmarks (GtkFileSelection *fs);
639 static void gtk_file_selection_load_masks(GtkFileSelection *fs);
641 static gint gtk_file_selection_show_fileop_menu (GtkCList *clist,
643 GtkFileSelection *fs);
646 static GtkWindowClass *parent_class = NULL;
648 /* Saves errno when something cmpl does fails. */
649 static gint cmpl_errno;
653 * Take the path currently in the file selection
654 * entry field and translate as necessary from
655 * a WIN32 style to CYGWIN32 style path. For
656 * instance translate:
657 * x:\somepath\file.jpg
659 * //x/somepath/file.jpg
661 * Replace the path in the selection text field.
662 * Return a boolean value concerning whether a
663 * translation had to be made.
666 translate_win32_path (GtkFileSelection *filesel)
672 * Retrieve the current path
674 path = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry));
677 * Translate only if this looks like a DOS-ish
678 * path... First handle any drive letters.
680 if (isalpha (path[0]) && (path[1] == ':')) {
682 * This part kind of stinks... It isn't possible
683 * to know if there is enough space in the current
684 * string for the extra character required in this
685 * conversion. Assume that there isn't enough space
686 * and use the set function on the text field to
687 * set the newly created string.
689 gchar *newPath = g_strdup_printf ("//%c/%s", path[0], (path + 3));
690 gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), newPath);
697 * Now, replace backslashes with forward slashes
700 if (strchr (path, '\\'))
703 for (index = 0; path[index] != '\0'; index++)
704 if (path[index] == '\\')
715 * Make prev and next inactive if their respective *
716 * histories are empty.
717 * Add facilities for handling hidden files and *
719 * Add an api to access the mask, and hidden files *
720 * check box? (prob not in 1.2.x series) *
723 /* Routine for applying mask to filenames *
724 * Need to be optimized to minimize recursion *
725 * help the for loop by looking for the next *
726 * instance of the mask character following *
727 * the '*'. ei *.c -- look for '.' *
728 * Also, swap all *? pairs (-> ?*), as that *
729 * will make it possible to look ahead (? *
730 * makes it very nondeterministic as in *?.c *
731 * which really is ?*.c *
734 static gint gtk_file_selection_match_char (gchar text, gchar *mask)
744 if (!strchr (mask,']')) return 0;
747 maskc = g_strdup(mask + 1); /* get the portion of mask inside []*/
748 (*(strchr (maskc + 1,']'))) = 0;
749 s = strlen ((char *)maskc);
751 for (x = 0 ; x < s ; x ++){
754 if (x == s) return 1;
755 nextc = maskc[x + 1];
759 if ((lastc <= text) && (nextc >= text))
765 else if ((lastc >= text) && (nextc <= text))
771 else if (text == maskc[x])
783 if (mask[0] == '?') return 1;
784 if (mask[0] == text) return 1;
790 static gint gtk_file_selection_match_mask1 (gchar *text, gchar *mask)
798 if (mask[0] == 0 && text[0] == 0) return 1;
802 for (tc = 0; tc <= strlen(text); tc++)
804 if (gtk_file_selection_match_mask1 (text + tc, mask + 1))
809 mc = gtk_file_selection_match_char (text[0], mask);
812 return gtk_file_selection_match_mask1 (text + 1, mask + mc);
817 static gint gtk_file_selection_match_mask (gchar *text, gchar *mask)
823 masks=g_strdup(mask);
825 emask=strchr(masks,'<');
828 emask=strchr(bmask,'>');
837 if((emask=strchr(bmask,',')) || (emask=strchr(bmask,';'))){
839 if (gtk_file_selection_match_mask1 (text, bmask)){
848 if(gtk_file_selection_match_mask1 (text, bmask)){
857 gtk_file_selection_load_bookmarks(GtkFileSelection *fs)
860 gchar *bookmark_file;
861 gchar *bookmark_data;
862 struct stat file_info;
866 BookmarkMenuStruct *item;
869 if(fs->bookmark_list){ //erase
870 list=fs->bookmark_list;
878 g_list_free (fs->bookmark_list);
879 fs->bookmark_list = NULL;
880 gtk_widget_destroy (fs->bookmark_menu);
883 fs->bookmark_menu=gtk_menu_new();
886 item=g_malloc(sizeof(item));
887 item->menu_item = gtk_menu_item_new();
888 gtk_widget_show(item->menu_item);
889 gtk_menu_append (GTK_MENU(fs->bookmark_menu), item->menu_item);
891 item=g_malloc(sizeof(item));
892 item->desc=g_strdup("Add bookmark");
893 item->path=g_strdup(".");
894 item->menu_item=gtk_menu_item_new_with_label (item->desc);
895 gtk_widget_show(item->menu_item);
896 //fs->bookmark_list=g_list_append(fs->bookmark_list,item);
898 gtk_menu_append (GTK_MENU(fs->bookmark_menu), item->menu_item);
900 item=g_malloc(sizeof(item));
901 item->desc=g_strdup("Edit bookmark");
902 item->path=g_strdup(".");
903 item->menu_item=gtk_menu_item_new_with_label (item->desc);
904 gtk_widget_show(item->menu_item);
905 //fs->bookmark_list=g_list_append(fs->bookmark_list,item);
907 gtk_menu_append (GTK_MENU(fs->bookmark_menu), item->menu_item);
909 bookmark_file=g_strconcat(g_get_home_dir(), BOOKMARK_FILE ,NULL);
910 if(!stat(bookmark_file,&file_info) && (file = open(bookmark_file, O_RDONLY )) > 0)
912 if(file_info.st_size <65536 )
914 bookmark_data=g_malloc(file_info.st_size);
916 if(file && read(file, bookmark_data, file_info.st_size))
920 while (cp < file_info.st_size)
922 while (cp < file_info.st_size && bookmark_data[cp] != '<' )
925 item=g_malloc(sizeof(BookmarkMenuStruct));
926 item->desc=g_strdup(bookmark_data+lp);
929 while (cp < file_info.st_size && bookmark_data[cp] != '>' )
934 item->path=g_strdup(bookmark_data+lp);
935 gtk_file_selection_add_bookmark ((gpointer) fs, (gpointer) item->desc, (gpointer) item->path);
939 while(cp < file_info.st_size && bookmark_data[cp] < 33 )
949 /* Add some default items, then save off to bookmarks file */
951 gtk_file_selection_add_bookmark ((gpointer) fs, "Home", "~/");
952 gtk_file_selection_add_bookmark ((gpointer) fs, "Root", "/");
954 gtk_file_selection_save_bookmarks ((gpointer) fs);
959 gtk_file_selection_add_bookmark (GtkFileSelection *fs, gchar *desc, gchar *path)
961 /* Add item to menu */
962 BookmarkMenuStruct *item;
963 item=g_malloc(sizeof(item));
964 item->desc = (gpointer) desc;
965 item->path = (gpointer) path;
966 item->menu_item=gtk_menu_item_new_with_label (item->desc);
967 gtk_widget_show(item->menu_item);
968 fs->bookmark_list=g_list_append(fs->bookmark_list,item);
969 gtk_signal_connect (GTK_OBJECT(item->menu_item), "activate",
970 (GtkSignalFunc) gtk_file_selection_bookmark_callback,
972 gtk_menu_insert (GTK_MENU(fs->bookmark_menu), item->menu_item, g_list_length(fs->bookmark_list) -1);
976 gtk_file_selection_save_bookmarks (GtkFileSelection *fs)
978 BookmarkMenuStruct *item;
979 gchar *bookmark_file;
984 bookmark_file=g_strconcat(g_get_home_dir(), BOOKMARK_FILE ,NULL);
986 if ((file = open(bookmark_file, O_CREAT | O_WRONLY | O_TRUNC, 0600)) > 0)
988 for (list = g_list_first (fs->bookmark_list); list != NULL; list = g_list_next(list)) {
990 item_data = g_strconcat(item->desc, " <", item->path, ">\n", NULL);
991 if (write (file, item_data, strlen(item_data)) != strlen(item_data)) {
1006 gtk_file_selection_load_masks(GtkFileSelection *fs)
1012 struct stat file_info;
1026 masks_file=g_strconcat(g_get_home_dir(), MASK_FILE,NULL); //put in #define
1027 if(!stat(masks_file,&file_info))
1029 if(file_info.st_size <65536 )
1031 masks_data=g_malloc(file_info.st_size);
1033 file = open(masks_file, O_RDONLY );
1035 if(file && read(file, masks_data, file_info.st_size))
1039 while (cp < file_info.st_size)
1041 while (cp < file_info.st_size && masks_data[cp] != '>' )
1045 if (masks_data[lp]=='<') { //if there was no description, strip off brackets
1049 // g_print("%s\n",masks_data+lp);
1050 fs->masks = g_list_append(fs->masks, g_strdup(masks_data+lp));
1052 while(cp < file_info.st_size && masks_data[cp] < 33 )
1063 /* masks is still null, fill it with default data... */
1065 fs->masks = g_list_append(fs->masks, "all files <*>");
1066 fs->masks = g_list_append(fs->masks, "mp3s/playlists <*.mp3,*.m3u>");
1067 fs->masks = g_list_append(fs->masks, "src/hdr <*.[CcHh],*.[Cc][Cc],*.[Hh][Hh],*.cpp>");
1068 fs->masks = g_list_append(fs->masks, "html docs <*.html,*.htm,*.HTM,*.php*,*.inc>");
1069 fs->masks = g_list_append(fs->masks, "images <*.png,*.jpg,*.jpeg,*.gif,*.xpm,*.tiff>");
1070 fs->masks = g_list_append(fs->masks, "package <*.rpm,*.deb>");
1071 fs->masks = g_list_append(fs->masks, "archive <*.tgz,*.tb2,*.tar*,*.zip,*.rar>");
1072 fs->masks = g_list_append(fs->masks, "compressed <*.Z,*.gz,*.bz2>");
1077 void gtk_file_selection_clear_masks (GtkFileSelection *filesel)
1081 g_return_if_fail (filesel != NULL);
1082 g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
1084 list = filesel->masks;
1087 g_free (list->data);
1090 filesel->masks = NULL;
1092 gtk_list_clear_items (GTK_LIST (GTK_COMBO (filesel->mask_entry)->list), 0, -1);
1095 void gtk_file_selection_set_masks (GtkFileSelection *filesel, const gchar **masks)
1097 g_return_if_fail (filesel != NULL);
1098 g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
1102 filesel->masks = g_list_append (filesel->masks, (gpointer)*masks);
1107 gtk_combo_set_popdown_strings (GTK_COMBO (filesel->mask_entry), filesel->masks);
1111 gtk_file_selection_get_type (void)
1113 static GtkType file_selection_type = 0;
1115 if (!file_selection_type)
1117 static const GtkTypeInfo filesel_info =
1120 sizeof (GtkFileSelection),
1121 sizeof (GtkFileSelectionClass),
1122 (GtkClassInitFunc) gtk_file_selection_class_init,
1123 (GtkObjectInitFunc) gtk_file_selection_init,
1124 /* reserved_1 */ NULL,
1125 /* reserved_2 */ NULL,
1126 (GtkClassInitFunc) NULL,
1129 file_selection_type = gtk_type_unique (GTK_TYPE_WINDOW, &filesel_info);
1132 return file_selection_type;
1136 gtk_file_selection_class_init (GtkFileSelectionClass *class)
1138 GtkObjectClass *object_class;
1139 GtkWidgetClass *widget_class;
1141 object_class = (GtkObjectClass*) class;
1143 parent_class = gtk_type_class (GTK_TYPE_WINDOW);
1145 widget_class = GTK_WIDGET_CLASS (class);
1147 widget_class->realize = gtk_file_selection_realize;
1148 object_class->destroy = gtk_file_selection_destroy;
1152 gtk_file_selection_init (GtkFileSelection *filesel)
1154 GtkWidget *entry_vbox;
1156 GtkWidget *list_vbox;
1157 GtkWidget *confirm_area;
1162 GtkWidget *pulldown_hbox;
1163 GtkWidget *scrolled_win;
1164 GtkWidget *mask_label;
1165 GtkWidget *bigframe;
1168 GtkWidget *menu_item;
1171 char *dir_title [2];
1172 char *file_title [2];
1174 filesel->cmpl_state = cmpl_init_state ();
1177 filesel->prev_history=NULL;
1178 filesel->next_history=NULL;
1179 filesel->saved_entry=NULL;
1180 filesel->bookmark_list=NULL;
1181 filesel->masks=NULL;
1182 filesel->selection_text = NULL;
1183 filesel->fileop_data = NULL;
1185 gtk_file_selection_load_masks(filesel);
1186 gtk_file_selection_load_bookmarks(filesel);
1188 /* The dialog-sized vertical box */
1189 filesel->main_vbox = gtk_vbox_new (FALSE, 0);
1190 gtk_container_set_border_width (GTK_CONTAINER (filesel), 0);
1191 gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox);
1192 gtk_widget_show (filesel->main_vbox);
1194 /* hbox for pulldown menu */
1195 pulldown_hbox = gtk_hbox_new (FALSE, 0);
1196 gtk_box_pack_start (GTK_BOX (filesel->main_vbox), pulldown_hbox, FALSE, FALSE, 0);
1197 gtk_widget_show (pulldown_hbox);
1199 /* The horizontal box containing create, rename etc. buttons */
1202 filesel->button_area = gtk_hbutton_box_new ();
1203 gtk_button_box_set_layout(GTK_BUTTON_BOX(filesel->button_area), GTK_BUTTONBOX_START);
1204 gtk_button_box_set_spacing(GTK_BUTTON_BOX(filesel->button_area), 0);
1205 gtk_box_pack_start (GTK_BOX (pulldown_hbox), filesel->button_area,
1207 gtk_button_box_set_child_size(GTK_BUTTON_BOX(filesel->button_area),0,0);
1208 gtk_button_box_set_child_ipadding(GTK_BUTTON_BOX(filesel->button_area),0,0);
1211 filesel->button_area = gtk_hbox_new (TRUE,0);
1212 //gtk_box_pack_start (GTK_BOX (pulldown_hbox), filesel->button_area,
1213 // FALSE, FALSE, 0);
1215 //gtk_widget_show (filesel->button_area);
1217 gtk_file_selection_show_fileop_buttons(filesel);
1218 /* frame to put the following hbox in */
1219 bigframe = gtk_frame_new (NULL);
1220 gtk_box_pack_start (GTK_BOX (filesel->main_vbox), bigframe, TRUE, TRUE, 0);
1221 gtk_frame_set_shadow_type (GTK_FRAME (bigframe), GTK_SHADOW_OUT);
1222 gtk_widget_show (bigframe);
1225 list_vbox = gtk_vbox_new (FALSE,3);
1226 gtk_widget_show(list_vbox);
1227 gtk_container_add (GTK_CONTAINER(bigframe), list_vbox);
1228 gtk_container_set_border_width (GTK_CONTAINER (list_vbox),2);
1229 gtk_widget_show (list_vbox);
1231 /* The horizontal box containing the directory and file listboxes */
1232 // list_hbox = gtk_hbox_new (FALSE, 3);
1233 //gtk_container_add (GTK_CONTAINER(bigframe), list_hbox);
1234 //gtk_container_set_border_width (GTK_CONTAINER (list_hbox), 3);
1235 // gtk_box_pack_start(GTK_BOX(list_vbox), list_hbox, FALSE,FALSE,0);
1236 // gtk_widget_show (list_hbox);
1238 hpaned=gtk_hpaned_new();
1239 gtk_widget_show(hpaned);
1240 gtk_container_set_border_width (GTK_CONTAINER (hpaned), 1);
1241 gtk_paned_set_gutter_size (GTK_PANED (hpaned), 10);
1242 gtk_box_pack_start (GTK_BOX(list_vbox), hpaned,TRUE,TRUE,0);
1244 /* vbox to put the buttons and directory listing in */
1245 vbox = gtk_vbox_new (FALSE, 3);
1246 gtk_widget_show (vbox);
1247 gtk_container_add(GTK_CONTAINER(hpaned),vbox);
1248 //gtk_box_pack_start (GTK_BOX (hpaned), vbox, FALSE, FALSE, 0);
1250 hbox = gtk_hbox_new (FALSE, 4);
1251 gtk_widget_show (hbox);
1252 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1254 // home_button = gtk_button_new_with_label (_("Home"));
1255 // gtk_widget_show (home_button);
1256 // gtk_signal_connect (GTK_OBJECT (home_button), "clicked",
1257 // (GtkSignalFunc) gtk_file_selection_home_button,
1258 // (gpointer) filesel);
1259 // gtk_box_pack_start (GTK_BOX (hbox), home_button, TRUE,TRUE, 0);
1261 /* Here we add the bookmark menu button */
1262 #define If we're going to make bookmark a menu, we don't need
1263 #define to keep it in the filesel structure
1264 button=gtk_button_new_with_label(_("Bookmarks"));
1265 gtk_widget_show(button);
1266 gtk_box_pack_start (GTK_BOX(hbox), button, FALSE,FALSE,0);
1267 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1268 (GtkSignalFunc) gtk_file_selection_bookmark_button,
1269 (gpointer) filesel);
1271 hbox2 = gtk_hbox_new (FALSE, 2);
1272 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
1273 gtk_widget_show(hbox2);
1276 button = gtk_button_new ();
1277 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1278 (GtkSignalFunc) gtk_file_selection_prev_button,
1279 (gpointer) filesel);
1280 gtk_widget_show (button);
1281 gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE,FALSE, 0);
1282 pixmap = create_pixmap (filesel->main_vbox, (gpointer) back_xpm);
1283 gtk_widget_show (pixmap);
1284 gtk_container_add (GTK_CONTAINER (button), pixmap);
1287 button = gtk_button_new ();
1288 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1289 (GtkSignalFunc) gtk_file_selection_up_button,
1290 (gpointer) filesel);
1291 gtk_widget_show (button);
1292 gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE,FALSE, 0);
1293 pixmap = create_pixmap (filesel->main_vbox, (gpointer) up_xpm);
1294 gtk_widget_show (pixmap);
1295 gtk_container_add (GTK_CONTAINER (button), pixmap);
1298 button = gtk_button_new ();
1299 gtk_widget_show (button);
1300 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1301 (GtkSignalFunc) gtk_file_selection_next_button,
1302 (gpointer) filesel);
1303 gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE,FALSE, 0);
1304 pixmap = create_pixmap (filesel->main_vbox, (gpointer) forward_xpm);
1305 gtk_widget_show (pixmap);
1306 gtk_container_add (GTK_CONTAINER (button), pixmap);
1308 /* refresh button */
1309 button = gtk_button_new ();
1310 gtk_widget_show (button);
1311 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1312 (GtkSignalFunc) gtk_file_selection_refresh_button,
1313 (gpointer) filesel);
1314 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE,FALSE, 0);
1315 pixmap = create_pixmap (filesel->main_vbox, (gpointer) refresh_xpm);
1316 gtk_widget_show (pixmap);
1317 gtk_container_add (GTK_CONTAINER (button), pixmap);
1319 /* menu for right click file operations */
1320 filesel->fileop_menu = gtk_menu_new();
1322 menu_item = gtk_menu_item_new_with_label (_("Rename..."));
1323 gtk_widget_show(menu_item);
1324 gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate",
1325 (GtkSignalFunc) gtk_file_selection_rename_file,
1326 (gpointer) filesel);
1327 gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item);
1329 menu_item = gtk_menu_item_new_with_label (_("Delete"));
1330 gtk_widget_show(menu_item);
1331 gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item);
1332 gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate",
1333 (GtkSignalFunc) gtk_file_selection_delete_file,
1334 (gpointer) filesel);
1336 menu_item = gtk_menu_item_new ();
1337 gtk_widget_show(menu_item);
1338 gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item);
1340 menu_item = gtk_menu_item_new_with_label (_("Create Directory..."));
1341 gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate",
1342 (GtkSignalFunc) gtk_file_selection_create_dir,
1343 (gpointer) filesel);
1344 gtk_widget_show(menu_item);
1345 gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item);
1347 menu_item = gtk_menu_item_new ();
1348 gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item);
1349 gtk_widget_show(menu_item);
1351 menu_item = gtk_menu_item_new_with_label (_("Properties..."));
1352 gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate",
1353 (GtkSignalFunc) gtk_file_selection_properties,
1354 (gpointer) filesel);
1355 gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item);
1356 gtk_widget_show(menu_item);
1358 /* The directories clist */
1359 dir_title[0] = _("Directories");
1360 dir_title[1] = NULL;
1361 filesel->dir_list = gtk_clist_new_with_titles (1, (gchar**) dir_title);
1362 gtk_widget_set_usize (filesel->dir_list, DIR_LIST_WIDTH, DIR_LIST_HEIGHT);
1363 gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "select_row",
1364 (GtkSignalFunc) gtk_file_selection_dir_button,
1365 (gpointer) filesel);
1366 gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "unselect_row",
1367 (GtkSignalFunc) gtk_file_selection_undir_button,
1368 (gpointer) filesel);
1369 gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "button_press_event",
1370 GTK_SIGNAL_FUNC(gtk_file_selection_show_fileop_menu),
1371 (gpointer) filesel);
1373 gtk_clist_column_titles_passive (GTK_CLIST (filesel->dir_list));
1375 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
1376 gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->dir_list);
1377 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
1378 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1379 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE,TRUE, 0);
1380 //gtk_container_add(GTK_CONTAINER(hpaned), scrolled_win);
1382 gtk_widget_show (filesel->dir_list);
1383 gtk_widget_show (scrolled_win);
1385 vbox = gtk_vbox_new (FALSE, 3);
1386 gtk_widget_show (vbox);
1387 gtk_container_add(GTK_CONTAINER(hpaned),vbox);
1388 /* vbox area for mask entry and files clist */
1390 hbox = gtk_hbox_new (FALSE, 2);
1391 gtk_widget_show (hbox);
1392 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1394 mask_label = gtk_label_new (_("Mask:"));
1395 gtk_widget_show (mask_label);
1396 gtk_box_pack_start (GTK_BOX (hbox), mask_label, FALSE, FALSE, 2);
1399 filesel->mask_entry = gtk_entry_new ();
1400 gtk_widget_show (filesel->mask_entry);
1401 gtk_signal_connect(GTK_OBJECT(filesel->mask_entry),"activate",
1402 (GtkSignalFunc) gtk_file_4_mask_entry_callback,
1403 (gpointer) filesel);
1404 gtk_box_pack_start (GTK_BOX (hbox),filesel->mask_entry, TRUE, TRUE, 0);
1407 filesel->mask_entry = gtk_combo_new ();
1408 gtk_widget_show (filesel->mask_entry);
1409 gtk_combo_set_value_in_list(GTK_COMBO(filesel->mask_entry),FALSE,FALSE);
1410 gtk_signal_connect(GTK_OBJECT(GTK_COMBO(filesel->mask_entry)->entry),"activate",
1411 (GtkSignalFunc) gtk_file_selection_mask_entry_callback,
1412 (gpointer) filesel);
1413 gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->mask_entry)->entry),"key-press-event",
1414 (GtkSignalFunc) gtk_file_selection_mask_entry_key_callback,
1415 (gpointer) filesel);
1417 gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->mask_entry)->list),"button-release-event",
1418 (GtkSignalFunc) gtk_file_selection_mask_entry_button_callback,
1419 (gpointer) filesel);
1420 gtk_box_pack_start (GTK_BOX (hbox),filesel->mask_entry, TRUE, TRUE, 0);
1423 gtk_combo_set_popdown_strings (GTK_COMBO (filesel->mask_entry), filesel->masks);
1426 /* The files clist */
1427 file_title[0] = _("Files");
1428 file_title[1] = NULL;
1429 filesel->file_list = gtk_clist_new_with_titles (1, (gchar**) file_title);
1430 gtk_widget_set_usize (filesel->file_list, FILE_LIST_WIDTH, FILE_LIST_HEIGHT);
1431 gtk_signal_connect (GTK_OBJECT (filesel->file_list), "select_row",
1432 (GtkSignalFunc) gtk_file_selection_file_button,
1433 (gpointer) filesel);
1434 gtk_signal_connect (GTK_OBJECT (filesel->file_list), "key-press-event",
1435 (GtkSignalFunc) gtk_file_selection_files_list_key_callback,
1436 (gpointer) filesel);
1438 gtk_signal_connect (GTK_OBJECT (filesel->file_list), "button_press_event",
1439 GTK_SIGNAL_FUNC(gtk_file_selection_show_fileop_menu),
1440 (gpointer) filesel);
1442 gtk_clist_column_titles_passive (GTK_CLIST (filesel->file_list));
1444 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
1445 gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->file_list);
1446 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
1447 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1448 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
1449 gtk_widget_show (filesel->file_list);
1450 gtk_widget_show (scrolled_win);
1452 /* action area for packing buttons into. */
1453 filesel->action_area = gtk_hbox_new (TRUE, 0);
1454 gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->action_area,
1456 gtk_widget_show (filesel->action_area);
1459 hbox=gtk_hbox_new(FALSE,0);
1460 gtk_box_pack_end (GTK_BOX (filesel->main_vbox), hbox, FALSE,FALSE, 0);
1461 gtk_widget_show (hbox);
1464 /* The selection entry widget */
1466 entry_vbox = gtk_vbox_new (FALSE, 0);
1467 gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 0);
1468 gtk_widget_show (entry_vbox);
1470 table = gtk_table_new ( 2, 2, FALSE );
1471 gtk_box_pack_start (GTK_BOX (entry_vbox), table, TRUE, TRUE, 0);
1472 gtk_container_set_border_width (GTK_CONTAINER (table), 4);
1473 gtk_table_set_row_spacings (GTK_TABLE (table), 2);
1474 gtk_table_set_col_spacings (GTK_TABLE (table), 4);
1477 label = gtk_label_new (_("Selection:"));
1478 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
1479 (GtkAttachOptions) (0),
1480 (GtkAttachOptions) (0), 0, 0);
1481 gtk_widget_show (label);
1484 filesel->selection_entry = gtk_entry_new ();
1485 gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event",
1486 (GtkSignalFunc) gtk_file_selection_key_press, filesel);
1487 gtk_table_attach (GTK_TABLE (table), filesel->selection_entry, 1, 2, 0, 1,
1488 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1489 (GtkAttachOptions) (0), 0, 0);
1490 gtk_widget_show (filesel->selection_entry);
1493 label = gtk_label_new (_("Directory:"));
1494 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
1495 (GtkAttachOptions) (0),
1496 (GtkAttachOptions) (0), 0, 0);
1497 gtk_widget_show (label);
1500 filesel->history_combo = gtk_combo_new();
1501 gtk_combo_set_value_in_list(GTK_COMBO(filesel->history_combo),FALSE,FALSE);
1502 gtk_table_attach (GTK_TABLE (table), filesel->history_combo, 1, 2, 1, 2,
1503 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1504 (GtkAttachOptions) (0), 0, 0);
1505 gtk_widget_show(filesel->history_combo);
1507 gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->entry),"key-press-event",
1508 (GtkSignalFunc) gtk_file_selection_history_combo_callback,
1509 (gpointer) filesel);
1511 gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"button-press-event",
1512 (GtkSignalFunc) gtk_file_selection_history_combo_list_callback,
1513 (gpointer) filesel);
1515 gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"key-press-event",
1516 (GtkSignalFunc) gtk_file_selection_history_combo_list_key_handler,
1517 (gpointer) filesel);
1519 filesel->selection_text = NULL;
1522 /* The OK/Cancel button area */
1523 confirm_area = gtk_hbutton_box_new ();
1524 gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area), GTK_BUTTONBOX_END);
1525 gtk_button_box_set_spacing(GTK_BUTTON_BOX(confirm_area), 5);
1526 gtk_box_pack_end (GTK_BOX (entry_vbox), confirm_area, FALSE, FALSE, 0);
1527 gtk_widget_show (confirm_area);
1530 filesel->ok_button = gtk_button_new_with_label (_("OK"));
1531 GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT);
1532 gtk_box_pack_start (GTK_BOX (confirm_area), filesel->ok_button, TRUE, TRUE, 0);
1533 gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event",
1534 (GtkSignalFunc) gtk_widget_grab_default,
1535 GTK_OBJECT (filesel->ok_button));
1536 gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate",
1537 (GtkSignalFunc) gtk_button_clicked,
1538 GTK_OBJECT (filesel->ok_button));
1539 gtk_widget_grab_default (filesel->ok_button);
1540 gtk_widget_show (filesel->ok_button);
1542 /* The Cancel button */
1543 filesel->cancel_button = gtk_button_new_with_label (_("Cancel"));
1544 GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT);
1545 gtk_box_pack_start (GTK_BOX (confirm_area), filesel->cancel_button, TRUE, TRUE, 0);
1546 gtk_widget_show (filesel->cancel_button);
1548 gtk_widget_show(table);
1552 filesel->selection_text = label = gtk_label_new ("");
1553 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1554 gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0);
1555 gtk_widget_show (label);
1559 if (!cmpl_state_okay (filesel->cmpl_state))
1563 sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno));
1566 gtk_label_set_text (GTK_LABEL (filesel->selection_text), err_buf);
1571 gtk_file_selection_populate (filesel, "", FALSE);
1574 gtk_widget_grab_focus (filesel->selection_entry);
1578 gtk_file_selection_new (const gchar *title)
1580 GtkFileSelection *filesel;
1582 filesel = gtk_type_new (GTK_TYPE_FILE_SELECTION);
1583 gtk_window_set_title (GTK_WINDOW (filesel), title);
1584 /* !!! put check here to figure out if screen > 640x480, if true
1585 We need to make the file selection dialog bigger. much bigger..
1586 or maybe we should keep it at a certan percentage of the screen
1589 gtk_window_set_default_size(GTK_WINDOW (filesel), 520, 420);
1590 return GTK_WIDGET (filesel);
1594 gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel)
1596 g_return_if_fail (filesel != NULL);
1597 g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
1601 /* delete, create directory, and rename */
1603 if (!filesel->fileop_c_dir)
1605 filesel->fileop_c_dir = gtk_button_new_with_label (_("MkDir"));
1606 gtk_signal_connect (GTK_OBJECT (filesel->fileop_c_dir), "clicked",
1607 (GtkSignalFunc) gtk_file_selection_create_dir,
1608 (gpointer) filesel);
1609 gtk_box_pack_start (GTK_BOX (filesel->button_area),
1610 filesel->fileop_c_dir, TRUE,TRUE, 0);
1611 gtk_widget_show (filesel->fileop_c_dir);
1614 if (!filesel->fileop_del_file)
1616 filesel->fileop_del_file = gtk_button_new_with_label (_("Delete"));
1617 gtk_signal_connect (GTK_OBJECT (filesel->fileop_del_file), "clicked",
1618 (GtkSignalFunc) gtk_file_selection_delete_file,
1619 (gpointer) filesel);
1620 gtk_box_pack_start (GTK_BOX (filesel->button_area),
1621 filesel->fileop_del_file, TRUE,TRUE, 0);
1622 gtk_widget_show (filesel->fileop_del_file);
1625 if (!filesel->fileop_ren_file)
1627 filesel->fileop_ren_file = gtk_button_new_with_label (_("Rename"));
1628 gtk_signal_connect (GTK_OBJECT (filesel->fileop_ren_file), "clicked",
1629 (GtkSignalFunc) gtk_file_selection_rename_file,
1630 (gpointer) filesel);
1631 gtk_box_pack_start (GTK_BOX (filesel->button_area),
1632 filesel->fileop_ren_file, TRUE,TRUE, 0);
1633 gtk_widget_show (filesel->fileop_ren_file);
1636 gtk_widget_queue_resize(GTK_WIDGET(filesel));
1641 gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel)
1643 g_return_if_fail (filesel != NULL);
1644 g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
1648 if (filesel->fileop_ren_file)
1650 gtk_widget_destroy (filesel->fileop_ren_file);
1651 filesel->fileop_ren_file = NULL;
1654 if (filesel->fileop_del_file)
1656 gtk_widget_destroy (filesel->fileop_del_file);
1657 filesel->fileop_del_file = NULL;
1660 if (filesel->fileop_c_dir)
1662 gtk_widget_destroy (filesel->fileop_c_dir);
1663 filesel->fileop_c_dir = NULL;
1671 gtk_file_selection_set_filename (GtkFileSelection *filesel,
1672 const gchar *filename)
1674 char buf[MAXPATHLEN];
1675 const char *name, *last_slash;
1677 g_return_if_fail (filesel != NULL);
1678 g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
1679 g_return_if_fail (filename != NULL);
1681 last_slash = strrchr (filename, '/');
1690 gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1);
1692 strncpy (buf, filename, len);
1695 name = last_slash + 1;
1698 gtk_file_selection_populate (filesel, buf, FALSE);
1700 if (filesel->selection_entry)
1701 gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name);
1705 gtk_file_selection_get_filename (GtkFileSelection *filesel)
1707 static char nothing[2] = "";
1711 g_return_val_if_fail (filesel != NULL, nothing);
1712 g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing);
1714 text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry));
1717 filename = cmpl_completion_fullname (text, filesel->cmpl_state);
1725 gtk_file_selection_complete (GtkFileSelection *filesel,
1726 const gchar *pattern)
1731 g_return_if_fail (filesel != NULL);
1732 g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
1733 g_return_if_fail (pattern != NULL);
1735 if (filesel->selection_entry)
1736 gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), pattern);
1738 if(strchr(pattern,'*') || strchr(pattern,'?'))
1740 for(x=strlen(pattern);x>=0;x--)
1742 if(pattern[x]=='/') break;
1744 gtk_entry_set_text(GTK_ENTRY(filesel->mask_entry),g_strdup(pattern+x+1));
1746 if(filesel->mask) g_free(filesel->mask);
1748 filesel->mask=g_strdup(pattern+x+1);
1749 new_pattern=g_strdup(pattern);
1751 gtk_file_selection_populate (filesel, (gchar*) new_pattern, TRUE);
1752 g_free(new_pattern);
1756 gtk_file_selection_populate (filesel, (gchar*) pattern, TRUE);
1761 gtk_file_selection_realize (GtkWidget *widget)
1763 GtkFileSelection *filesel;
1764 const gchar *masks[] = { "All Files <*>", NULL };
1766 g_return_if_fail (widget != NULL);
1767 g_return_if_fail (GTK_IS_FILE_SELECTION (widget));
1769 filesel = GTK_FILE_SELECTION (widget);
1771 /* make sure that we have at least one mask */
1772 if (!filesel->masks)
1773 gtk_file_selection_set_masks (filesel, masks);
1775 filesel->mask = g_strdup ((gchar*) filesel->masks->data);
1776 gtk_file_selection_populate (filesel, "", FALSE);
1779 if (GTK_WIDGET_CLASS (parent_class)->realize)
1780 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
1784 gtk_file_selection_destroy (GtkObject *object)
1786 GtkFileSelection *filesel;
1789 g_return_if_fail (object != NULL);
1790 g_return_if_fail (GTK_IS_FILE_SELECTION (object));
1792 filesel = GTK_FILE_SELECTION (object);
1794 if (filesel->fileop_dialog)
1795 gtk_widget_destroy (filesel->fileop_dialog);
1797 if (filesel->next_history)
1799 list = filesel->next_history;
1802 g_free (list->data);
1806 g_list_free (filesel->next_history);
1807 filesel->next_history = NULL;
1809 if (filesel->prev_history)
1811 list = filesel->prev_history;
1814 g_free (list->data);
1818 g_list_free (filesel->prev_history);
1819 filesel->prev_history = NULL;
1823 g_free (filesel->mask);
1824 filesel->mask = NULL;
1827 cmpl_free_state (filesel->cmpl_state);
1828 filesel->cmpl_state = NULL;
1830 if (GTK_OBJECT_CLASS (parent_class)->destroy)
1831 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1834 /* Begin file operations callbacks */
1837 gtk_file_selection_show_fileop_menu (GtkCList *clist, GdkEvent *event, GtkFileSelection *fs)
1839 GdkEventButton *event_button;
1841 g_return_val_if_fail (clist != NULL, FALSE);
1842 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
1843 g_return_val_if_fail (event != NULL, FALSE);
1844 g_return_val_if_fail (fs != NULL, FALSE);
1845 g_return_val_if_fail (GTK_FILE_SELECTION (fs), FALSE);
1847 if (event->type == GDK_BUTTON_PRESS)
1849 event_button = (GdkEventButton *) event;
1850 if (event_button->button == 3)
1853 gtk_menu_popup (GTK_MENU (fs->fileop_menu), NULL, NULL, NULL, NULL,
1854 event_button->button, event_button->time);
1863 gtk_file_selection_fileop_error (GtkFileSelection *fs, gchar *error_message)
1870 g_return_if_fail (error_message != NULL);
1873 dialog = gtk_dialog_new ();
1875 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
1876 (GtkSignalFunc) gtk_file_selection_fileop_destroy,
1879 gtk_window_set_title (GTK_WINDOW (dialog), _("Error"));
1880 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1882 /* If file dialog is grabbed, make this dialog modal too */
1883 /* When error dialog is closed, file dialog will be grabbed again */
1884 if (GTK_WINDOW(fs)->modal)
1885 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
1887 vbox = gtk_vbox_new(FALSE, 0);
1888 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1889 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox,
1891 gtk_widget_show(vbox);
1893 label = gtk_label_new(error_message);
1894 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1895 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
1896 gtk_widget_show(label);
1898 /* yes, we free it */
1899 g_free (error_message);
1902 button = gtk_button_new_with_label (_("Close"));
1903 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1904 (GtkSignalFunc) gtk_widget_destroy,
1906 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
1907 button, TRUE, TRUE, 0);
1908 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1909 gtk_widget_grab_default(button);
1910 gtk_widget_show (button);
1912 gtk_widget_show (dialog);
1916 gtk_file_selection_fileop_destroy (GtkWidget *widget, gpointer data)
1918 GtkFileSelection *fs = data;
1920 g_return_if_fail (fs != NULL);
1921 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
1923 fs->fileop_dialog = NULL;
1924 g_free (fs->fileop_data);
1925 fs->fileop_data = NULL;
1930 gtk_file_selection_create_dir_confirmed (GtkWidget *widget, gpointer data)
1932 GtkFileSelection *fs = data;
1937 CompletionState *cmpl_state;
1939 g_return_if_fail (fs != NULL);
1940 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
1942 dirname = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry));
1943 cmpl_state = (CompletionState*) fs->cmpl_state;
1944 path = cmpl_reference_position (cmpl_state);
1946 full_path = g_strconcat (path, "/", dirname, NULL);
1947 if ( (mkdir (full_path, 0755) < 0) )
1949 buf = g_strconcat ("Error creating directory \"", dirname, "\": ",
1950 g_strerror(errno), NULL);
1951 gtk_file_selection_fileop_error (fs, buf);
1955 gtk_widget_destroy (fs->fileop_dialog);
1956 gtk_file_selection_populate (fs, "", FALSE);
1960 gtk_file_selection_create_dir (gpointer data)
1962 GtkFileSelection *fs = data;
1968 g_return_if_fail (fs != NULL);
1969 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
1971 if (fs->fileop_dialog)
1975 fs->fileop_dialog = dialog = gtk_dialog_new ();
1976 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
1977 (GtkSignalFunc) gtk_file_selection_fileop_destroy,
1979 gtk_window_set_title (GTK_WINDOW (dialog), _("Create Directory"));
1980 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1982 /* If file dialog is grabbed, grab option dialog */
1983 /* When option dialog is closed, file dialog will be grabbed again */
1984 if (GTK_WINDOW(fs)->modal)
1985 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
1987 vbox = gtk_vbox_new(FALSE, 0);
1988 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1989 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox,
1991 gtk_widget_show(vbox);
1993 label = gtk_label_new(_("Directory name:"));
1994 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1995 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
1996 gtk_widget_show(label);
1998 /* The directory entry widget */
1999 fs->fileop_entry = gtk_entry_new ();
2000 gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry,
2002 GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT);
2003 gtk_widget_show (fs->fileop_entry);
2006 button = gtk_button_new_with_label (_("Create"));
2007 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2008 (GtkSignalFunc) gtk_file_selection_create_dir_confirmed,
2010 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2011 button, TRUE, TRUE, 0);
2012 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2013 gtk_widget_show(button);
2015 button = gtk_button_new_with_label (_("Cancel"));
2016 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2017 (GtkSignalFunc) gtk_widget_destroy,
2019 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2020 button, TRUE, TRUE, 0);
2021 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2022 gtk_widget_grab_default(button);
2023 gtk_widget_show (button);
2025 gtk_widget_show (dialog);
2029 gtk_file_selection_delete_file_confirmed (GtkWidget *widget, gpointer data)
2031 GtkFileSelection *fs = data;
2032 CompletionState *cmpl_state;
2037 g_return_if_fail (fs != NULL);
2038 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2040 cmpl_state = (CompletionState*) fs->cmpl_state;
2041 path = cmpl_reference_position (cmpl_state);
2043 full_path = g_strconcat (path, "/", fs->fileop_file, NULL);
2044 if ( (unlink (full_path) < 0) )
2046 buf = g_strconcat ("Error deleting file \"", fs->fileop_file, "\": ",
2047 g_strerror(errno), NULL);
2048 gtk_file_selection_fileop_error (fs, buf);
2052 gtk_widget_destroy (fs->fileop_dialog);
2053 gtk_file_selection_populate (fs, "", FALSE);
2057 gtk_file_selection_delete_file (gpointer data)
2059 GtkFileSelection *fs = data;
2067 g_return_if_fail (fs != NULL);
2068 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2070 if (fs->fileop_dialog)
2073 filename = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry));
2074 if (strlen(filename) < 1)
2077 fs->fileop_file = filename;
2080 fs->fileop_dialog = dialog = gtk_dialog_new ();
2081 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
2082 (GtkSignalFunc) gtk_file_selection_fileop_destroy,
2084 gtk_window_set_title (GTK_WINDOW (dialog), _("Delete File"));
2085 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
2087 /* If file dialog is grabbed, grab option dialog */
2088 /* When option dialog is closed, file dialog will be grabbed again */
2089 if (GTK_WINDOW(fs)->modal)
2090 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
2092 vbox = gtk_vbox_new(FALSE, 0);
2093 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
2094 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox,
2096 gtk_widget_show(vbox);
2098 buf = g_strconcat ("Really delete file \"", filename, "\" ?", NULL);
2099 label = gtk_label_new(buf);
2100 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
2101 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
2102 gtk_widget_show(label);
2106 button = gtk_button_new_with_label (_("Delete"));
2107 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2108 (GtkSignalFunc) gtk_file_selection_delete_file_confirmed,
2110 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2111 button, TRUE, TRUE, 0);
2112 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2113 gtk_widget_show(button);
2115 button = gtk_button_new_with_label (_("Cancel"));
2116 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2117 (GtkSignalFunc) gtk_widget_destroy,
2119 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2120 button, TRUE, TRUE, 0);
2121 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2122 gtk_widget_grab_default(button);
2123 gtk_widget_show (button);
2125 gtk_widget_show (dialog);
2130 gtk_file_selection_rename_file_confirmed (GtkWidget *widget, gpointer data)
2132 GtkFileSelection *fs = data;
2136 gchar *new_filename;
2137 gchar *old_filename;
2138 CompletionState *cmpl_state;
2140 g_return_if_fail (fs != NULL);
2141 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2143 file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry));
2144 cmpl_state = (CompletionState*) fs->cmpl_state;
2145 path = cmpl_reference_position (cmpl_state);
2147 new_filename = g_strconcat (path, "/", file, NULL);
2148 old_filename = g_strconcat (path, "/", fs->fileop_file, NULL);
2150 if (strcmp (new_filename, old_filename))
2151 if ((rename (old_filename, new_filename)) < 0)
2153 buf = g_strconcat ("Error renaming file \"", file, "\": ",
2154 g_strerror(errno), NULL);
2155 gtk_file_selection_fileop_error (fs, buf);
2157 g_free (new_filename);
2158 g_free (old_filename);
2160 gtk_widget_destroy (fs->fileop_dialog);
2161 gtk_file_selection_populate (fs, "", FALSE);
2165 gtk_file_selection_file_mode_confirmed (GtkWidget *widget, gpointer data)
2167 GtkFileSelection *fs = data;
2168 PropertiesPrivate *priv = fs->fileop_data;
2169 CompletionState *cmpl_state;
2170 gchar *filename, *file, *path;
2173 mode = gtk_file_selection_properties_get_mode (priv);
2175 file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry));
2176 cmpl_state = (CompletionState*) fs->cmpl_state;
2177 path = cmpl_reference_position (cmpl_state);
2179 filename = g_strconcat (path, "/", file, NULL);
2180 if (chmod (filename, mode) == -1)
2182 gchar *buf = g_strconcat ("Error changing file mode of \"", filename, "\": ",
2183 g_strerror (errno), NULL);
2184 gtk_file_selection_fileop_error (fs, buf);
2185 gtk_widget_destroy (fs->fileop_dialog);
2186 gtk_file_selection_populate (fs, "", FALSE);
2189 gtk_file_selection_rename_file_confirmed (widget, data);
2195 gtk_file_selection_rename_file (gpointer data)
2197 GtkFileSelection *fs = data;
2204 g_return_if_fail (fs != NULL);
2205 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2207 if (fs->fileop_dialog)
2210 fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry));
2211 if (strlen(fs->fileop_file) < 1)
2215 fs->fileop_dialog = dialog = gtk_dialog_new ();
2216 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
2217 (GtkSignalFunc) gtk_file_selection_fileop_destroy,
2219 gtk_window_set_title (GTK_WINDOW (dialog), _("Rename File"));
2220 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
2222 /* If file dialog is grabbed, grab option dialog */
2223 /* When option dialog closed, file dialog will be grabbed again */
2224 if (GTK_WINDOW(fs)->modal)
2225 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
2227 vbox = gtk_vbox_new(FALSE, 0);
2228 gtk_container_set_border_width (GTK_CONTAINER(vbox), 8);
2229 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox,
2231 gtk_widget_show(vbox);
2233 buf = g_strconcat ("Rename file \"", fs->fileop_file, "\" to:", NULL);
2234 label = gtk_label_new(buf);
2235 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
2236 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
2237 gtk_widget_show(label);
2240 /* New filename entry */
2241 fs->fileop_entry = gtk_entry_new ();
2242 gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry,
2244 GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT);
2245 gtk_widget_show (fs->fileop_entry);
2247 gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file);
2248 gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry),
2249 0, strlen (fs->fileop_file));
2252 button = gtk_button_new_with_label (_("Rename"));
2253 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2254 (GtkSignalFunc) gtk_file_selection_rename_file_confirmed,
2256 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2257 button, TRUE, TRUE, 0);
2258 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2259 gtk_widget_show(button);
2261 button = gtk_button_new_with_label (_("Cancel"));
2262 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2263 (GtkSignalFunc) gtk_widget_destroy,
2265 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2266 button, TRUE, TRUE, 0);
2267 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2268 gtk_widget_grab_default(button);
2269 gtk_widget_show (button);
2271 gtk_widget_show (dialog);
2275 gtk_file_selection_properties_get_mode (PropertiesPrivate* priv)
2279 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[0])))
2281 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[1])))
2283 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[2])))
2285 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[3])))
2287 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[4])))
2289 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[5])))
2291 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[6])))
2293 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[7])))
2295 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[8])))
2297 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[9])))
2299 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[10])))
2301 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[11])))
2308 gtk_file_selection_properties_update_mode (GtkWidget *widget, gpointer data)
2310 GtkFileSelection *fs = data;
2311 PropertiesPrivate *priv = fs->fileop_data;
2314 sprintf (str, "(%.4o)", gtk_file_selection_properties_get_mode (priv));
2315 gtk_label_set (GTK_LABEL (priv->mode_label), str);
2319 gtk_file_selection_properties (gpointer data)
2321 GtkFileSelection *fs = data;
2327 GtkWidget *notebook;
2329 GtkWidget *hseparator;
2331 GtkWidget *togglebutton;
2332 struct stat statbuf;
2338 gchar timeBuf[TIME_STRING_BUF];
2340 PropertiesPrivate *priv;
2343 g_return_if_fail (fs != NULL);
2344 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2346 if (fs->fileop_dialog)
2350 fs->fileop_dialog = dialog = gtk_dialog_new ();
2351 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
2352 (GtkSignalFunc) gtk_file_selection_fileop_destroy,
2354 priv = fs->fileop_data = g_malloc (sizeof (PropertiesPrivate));
2356 gtk_window_set_title (GTK_WINDOW (dialog), ("Properties"));
2357 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
2359 /* If file dialog is grabbed, grab option dialog */
2360 /* When option dialog closed, file dialog will be grabbed again */
2361 if (GTK_WINDOW(fs)->modal)
2362 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
2364 /* Dialog guts go here */
2365 notebook = gtk_notebook_new ();
2366 gtk_widget_show (notebook);
2367 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), notebook, TRUE, TRUE, 0);
2368 gtk_container_set_border_width (GTK_CONTAINER (notebook), 8);
2370 path = cmpl_reference_position(fs->cmpl_state);
2371 fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry));
2372 filename = g_strconcat(path, "/", fs->fileop_file, NULL);
2373 if (strlen(fs->fileop_file) > 0 && !(stat(filename, &statbuf)))
2376 table = gtk_table_new (9, 2, FALSE);
2377 gtk_widget_show (table);
2378 gtk_container_add (GTK_CONTAINER (notebook), table);
2379 gtk_container_set_border_width (GTK_CONTAINER (table), 5);
2380 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
2381 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
2383 label = gtk_label_new (_("Statistics"));
2384 gtk_widget_show (label);
2385 gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum), label);
2387 /* path and filename */
2388 label = gtk_label_new (_("Path:"));
2389 gtk_widget_show (label);
2390 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2391 (GtkAttachOptions) (GTK_FILL),
2392 (GtkAttachOptions) (0), 0, 0);
2393 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2395 label = gtk_label_new (_(path));
2396 gtk_widget_show (label);
2397 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
2398 (GtkAttachOptions) (GTK_FILL),
2399 (GtkAttachOptions) (0), 0, 0);
2400 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
2401 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2403 label = gtk_label_new (_("File Name:"));
2404 gtk_widget_show (label);
2405 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2406 (GtkAttachOptions) (GTK_FILL),
2407 (GtkAttachOptions) (0), 0, 0);
2408 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2410 fs->fileop_entry = entry = gtk_entry_new ();
2411 gtk_widget_show (entry);
2412 gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2,
2413 (GtkAttachOptions) (GTK_FILL),
2414 (GtkAttachOptions) (0), 0, 0);
2415 gtk_entry_set_text (GTK_ENTRY (entry), fs->fileop_file);
2416 if (access (filename, W_OK))
2417 gtk_widget_set_sensitive( GTK_WIDGET (entry), FALSE);
2419 hseparator = gtk_hseparator_new ();
2420 gtk_widget_show (hseparator);
2421 gtk_table_attach (GTK_TABLE (table), hseparator, 0, 2, 2, 3,
2422 (GtkAttachOptions) (GTK_FILL),
2423 (GtkAttachOptions) (GTK_FILL), 0, 0);
2425 /* file type and size */
2426 label = gtk_label_new (_("Type:"));
2427 gtk_widget_show (label);
2428 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
2429 (GtkAttachOptions) (GTK_FILL),
2430 (GtkAttachOptions) (0), 0, 0);
2431 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2433 switch (statbuf.st_mode & S_IFMT)
2436 buf = g_strdup ("Socket");
2439 buf = g_strdup ("Symbolic link");
2442 buf = g_strdup ("File");
2445 buf = g_strdup ("Block device");
2448 buf = g_strdup ("Directory");
2451 buf = g_strdup ("Character device");
2454 buf = g_strdup ("First-in/first-out pipe");
2457 buf = g_strdup ("Unknown");
2461 label = gtk_label_new (buf);
2462 gtk_widget_show (label);
2463 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 3, 4,
2464 (GtkAttachOptions) (GTK_FILL),
2465 (GtkAttachOptions) (0), 0, 0);
2466 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2468 label = gtk_label_new (_("Size:"));
2469 gtk_widget_show (label);
2470 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
2471 (GtkAttachOptions) (GTK_FILL),
2472 (GtkAttachOptions) (0), 0, 0);
2473 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2475 label = gtk_label_new (_(g_strdup_printf ("%ld bytes", statbuf.st_size)));
2476 gtk_widget_show (label);
2477 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 4, 5,
2478 (GtkAttachOptions) (GTK_FILL),
2479 (GtkAttachOptions) (0), 0, 0);
2480 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2482 hseparator = gtk_hseparator_new ();
2483 gtk_widget_show (hseparator);
2484 gtk_table_attach (GTK_TABLE (table), hseparator, 0, 2, 5, 6,
2485 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2486 (GtkAttachOptions) (GTK_FILL), 0, 0);
2489 label = gtk_label_new (_("Created:"));
2490 gtk_widget_show (label);
2491 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 6, 7,
2492 (GtkAttachOptions) (GTK_FILL),
2493 (GtkAttachOptions) (0), 0, 0);
2494 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2496 strftime (timeBuf, TIME_STRING_BUF, "%a %b %d %X %Y", localtime(&statbuf.st_mtime));
2497 label = gtk_label_new (_(timeBuf));
2498 gtk_widget_show (label);
2499 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 6, 7,
2500 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2501 (GtkAttachOptions) (0), 0, 0);
2502 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2506 label = gtk_label_new (_("Modified:"));
2507 gtk_widget_show (label);
2508 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 7, 8,
2509 (GtkAttachOptions) (GTK_FILL),
2510 (GtkAttachOptions) (0), 0, 0);
2511 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2513 strftime (timeBuf, TIME_STRING_BUF, "%a %b %d %X %Y", localtime(&statbuf.st_mtime));
2514 label = gtk_label_new (_(timeBuf));
2515 gtk_widget_show (label);
2516 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 7, 8,
2517 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2518 (GtkAttachOptions) (0), 0, 0);
2519 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
2520 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2523 label = gtk_label_new (_("Accessed:"));
2524 gtk_widget_show (label);
2525 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 8, 9,
2526 (GtkAttachOptions) (GTK_FILL),
2527 (GtkAttachOptions) (0), 0, 0);
2528 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2530 strftime (timeBuf, TIME_STRING_BUF, "%a %b %d %X %Y", localtime(&statbuf.st_atime));
2531 label = gtk_label_new (_(timeBuf));
2532 gtk_widget_show (label);
2533 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 8, 9,
2534 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2535 (GtkAttachOptions) (0), 0, 0);
2536 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
2537 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2539 /* permissions page */
2540 vbox = gtk_vbox_new (FALSE, 4);
2541 gtk_widget_show (vbox);
2542 gtk_container_add (GTK_CONTAINER (notebook), vbox);
2543 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
2545 label = gtk_label_new (_("Permissions"));
2546 gtk_widget_show (label);
2547 gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum), label);
2551 table = gtk_table_new (2, 2, FALSE);
2552 gtk_widget_show (table);
2553 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
2554 gtk_table_set_row_spacings (GTK_TABLE (table), 2);
2555 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
2557 label = gtk_label_new (_("Owner:"));
2558 gtk_widget_show (label);
2559 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2560 (GtkAttachOptions) (GTK_FILL),
2561 (GtkAttachOptions) (0), 0, 0);
2562 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2564 entry = gtk_entry_new();
2565 gtk_widget_show (entry);
2566 gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1,
2567 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2568 (GtkAttachOptions) (0), 0, 0);
2569 if ((pw = getpwuid(statbuf.st_uid)))
2570 gtk_entry_set_text(GTK_ENTRY (entry), pw->pw_name);
2572 gtk_entry_set_text(GTK_ENTRY (entry), (gpointer) statbuf.st_uid);
2573 if (access (filename, W_OK) || (getuid() != 0))
2574 gtk_widget_set_sensitive( GTK_WIDGET (entry), FALSE);
2577 label = gtk_label_new (_("Group:"));
2578 gtk_widget_show (label);
2579 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2580 (GtkAttachOptions) (GTK_FILL),
2581 (GtkAttachOptions) (0), 0, 0);
2582 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2584 entry = gtk_entry_new();
2585 gtk_widget_show (entry);
2586 gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2,
2587 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2588 (GtkAttachOptions) (0), 0, 0);
2589 if ((gp = getgrgid(statbuf.st_gid)))
2590 gtk_entry_set_text(GTK_ENTRY (entry), gp->gr_name);
2592 gtk_entry_set_text(GTK_ENTRY (entry), (gpointer) statbuf.st_gid);
2593 if (access (filename, W_OK) || (getuid() != 0))
2594 gtk_widget_set_sensitive( GTK_WIDGET (entry), FALSE);
2597 hseparator = gtk_hseparator_new ();
2598 gtk_widget_show (hseparator);
2599 gtk_box_pack_start (GTK_BOX (vbox), hseparator, FALSE, TRUE, 0);
2602 table = gtk_table_new (4, 5, TRUE);
2603 gtk_widget_show (table);
2604 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2605 gtk_table_set_row_spacings (GTK_TABLE (table), 2);
2606 gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2607 if (access (filename, W_OK) || ((getuid() != statbuf.st_uid) && getuid() != 0))
2608 gtk_widget_set_sensitive (GTK_WIDGET (table), FALSE);
2610 hbox = gtk_hbox_new (FALSE, 1);
2611 gtk_widget_show (hbox);
2612 gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 0, 1,
2613 (GtkAttachOptions) (GTK_FILL),
2614 (GtkAttachOptions) (GTK_FILL), 0, 0);
2616 priv->mode_label = label = gtk_label_new ("(0000)");
2617 gtk_widget_show (label);
2618 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
2620 label = gtk_label_new (_("Read"));
2621 gtk_widget_show (label);
2622 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
2623 (GtkAttachOptions) (0),
2624 (GtkAttachOptions) (0), 0, 0);
2626 label = gtk_label_new (_("Write"));
2627 gtk_widget_show (label);
2628 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
2629 (GtkAttachOptions) (0),
2630 (GtkAttachOptions) (0), 0, 0);
2632 label = gtk_label_new (_("Exec"));
2633 gtk_widget_show (label);
2634 gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1,
2635 (GtkAttachOptions) (0),
2636 (GtkAttachOptions) (0), 0, 0);
2638 label = gtk_label_new (_("Special"));
2639 gtk_widget_show (label);
2640 gtk_table_attach (GTK_TABLE (table), label, 4, 5, 0, 1,
2641 (GtkAttachOptions) (0),
2642 (GtkAttachOptions) (0), 0, 0);
2645 label = gtk_label_new (_("User:"));
2646 gtk_widget_show (label);
2647 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2648 (GtkAttachOptions) (GTK_FILL),
2649 (GtkAttachOptions) (0), 0, 0);
2650 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2652 priv->mode_buttons[0] = togglebutton = gtk_toggle_button_new_with_label ("");
2653 gtk_widget_show (togglebutton);
2654 gtk_table_attach (GTK_TABLE (table), togglebutton, 1, 2, 1, 2,
2655 (GtkAttachOptions) (GTK_FILL),
2656 (GtkAttachOptions) (0), 0, 0);
2657 if ((statbuf.st_mode & ~(S_IFMT)) & S_IRUSR)
2658 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2660 priv->mode_buttons[1] = togglebutton = gtk_toggle_button_new_with_label ("");
2661 gtk_widget_show (togglebutton);
2662 gtk_table_attach (GTK_TABLE (table), togglebutton, 2, 3, 1, 2,
2663 (GtkAttachOptions) (GTK_FILL),
2664 (GtkAttachOptions) (0), 0, 0);
2665 if ((statbuf.st_mode & ~(S_IFMT)) & S_IWUSR)
2666 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2668 priv->mode_buttons[2] = togglebutton = gtk_toggle_button_new_with_label ("");
2669 gtk_widget_show (togglebutton);
2670 gtk_table_attach (GTK_TABLE (table), togglebutton, 3, 4, 1, 2,
2671 (GtkAttachOptions) (GTK_FILL),
2672 (GtkAttachOptions) (0), 0, 0);
2673 if ((statbuf.st_mode & ~(S_IFMT)) & S_IXUSR)
2674 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2676 priv->mode_buttons[3] = togglebutton = gtk_toggle_button_new_with_label ("");
2677 gtk_widget_show (togglebutton);
2678 gtk_table_attach (GTK_TABLE (table), togglebutton, 4, 5, 1, 2,
2679 (GtkAttachOptions) (GTK_FILL),
2680 (GtkAttachOptions) (0), 0, 0);
2681 if ((statbuf.st_mode & ~(S_IFMT)) & S_ISUID)
2682 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2686 label = gtk_label_new (_("Group:"));
2687 gtk_widget_show (label);
2688 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
2689 (GtkAttachOptions) (GTK_FILL),
2690 (GtkAttachOptions) (0), 0, 0);
2691 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2693 priv->mode_buttons[4] = togglebutton = gtk_toggle_button_new_with_label ("");
2694 gtk_widget_show (togglebutton);
2695 gtk_table_attach (GTK_TABLE (table), togglebutton, 1, 2, 2, 3,
2696 (GtkAttachOptions) (GTK_FILL),
2697 (GtkAttachOptions) (0), 0, 0);
2698 if ((statbuf.st_mode & ~(S_IFMT)) & S_IRGRP)
2699 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2701 priv->mode_buttons[5] = togglebutton = gtk_toggle_button_new_with_label ("");
2702 gtk_widget_show (togglebutton);
2703 gtk_table_attach (GTK_TABLE (table), togglebutton, 2, 3, 2, 3,
2704 (GtkAttachOptions) (GTK_FILL),
2705 (GtkAttachOptions) (0), 0, 0);
2706 if ((statbuf.st_mode & ~(S_IFMT)) & S_IWGRP)
2707 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2709 priv->mode_buttons[6] = togglebutton = gtk_toggle_button_new_with_label ("");
2710 gtk_widget_show (togglebutton);
2711 gtk_table_attach (GTK_TABLE (table), togglebutton, 3, 4, 2, 3,
2712 (GtkAttachOptions) (GTK_FILL),
2713 (GtkAttachOptions) (0), 0, 0);
2714 if ((statbuf.st_mode & ~(S_IFMT)) & S_IXGRP)
2715 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2717 priv->mode_buttons[7] = togglebutton = gtk_toggle_button_new_with_label ("");
2718 gtk_widget_show (togglebutton);
2719 gtk_table_attach (GTK_TABLE (table), togglebutton, 4, 5, 2, 3,
2720 (GtkAttachOptions) (GTK_FILL),
2721 (GtkAttachOptions) (0), 0, 0);
2722 if ((statbuf.st_mode & ~(S_IFMT)) & S_ISGID)
2723 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2725 label = gtk_label_new (_("Other:"));
2726 gtk_widget_show (label);
2727 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
2728 (GtkAttachOptions) (GTK_FILL),
2729 (GtkAttachOptions) (0), 0, 0);
2730 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2732 priv->mode_buttons[8] = togglebutton = gtk_toggle_button_new_with_label ("");
2733 gtk_widget_show (togglebutton);
2734 gtk_table_attach (GTK_TABLE (table), togglebutton, 1, 2, 3, 4,
2735 (GtkAttachOptions) (GTK_FILL),
2736 (GtkAttachOptions) (0), 0, 0);
2737 if ((statbuf.st_mode & ~(S_IFMT)) & S_IROTH)
2738 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2740 priv->mode_buttons[9] = togglebutton = gtk_toggle_button_new_with_label ("");
2741 gtk_widget_show (togglebutton);
2742 gtk_table_attach (GTK_TABLE (table), togglebutton, 2, 3, 3, 4,
2743 (GtkAttachOptions) (GTK_FILL),
2744 (GtkAttachOptions) (0), 0, 0);
2745 if ((statbuf.st_mode & ~(S_IFMT)) & S_IWOTH)
2746 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2748 priv->mode_buttons[10] = togglebutton = gtk_toggle_button_new_with_label ("");
2749 gtk_widget_show (togglebutton);
2750 gtk_table_attach (GTK_TABLE (table), togglebutton, 3, 4, 3, 4,
2751 (GtkAttachOptions) (GTK_FILL),
2752 (GtkAttachOptions) (0), 0, 0);
2753 if ((statbuf.st_mode & ~(S_IFMT)) & S_IXOTH)
2754 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2756 priv->mode_buttons[11] = togglebutton = gtk_toggle_button_new_with_label ("");
2757 gtk_widget_show (togglebutton);
2758 gtk_table_attach (GTK_TABLE (table), togglebutton, 4, 5, 3, 4,
2759 (GtkAttachOptions) (GTK_FILL),
2760 (GtkAttachOptions) (0), 0, 0);
2761 if ((statbuf.st_mode & ~(S_IFMT)) & S_ISVTX)
2762 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE);
2764 for (i = 0; i < 12; i++)
2765 gtk_signal_connect (GTK_OBJECT (priv->mode_buttons[i]), "toggled",
2766 GTK_SIGNAL_FUNC (gtk_file_selection_properties_update_mode), fs);
2767 gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (priv->mode_buttons[0]));
2770 vbox = gtk_vbox_new (FALSE, 0);
2771 gtk_widget_show (vbox);
2772 gtk_container_add (GTK_CONTAINER (notebook), vbox);
2774 label = gtk_label_new (_("Global"));
2775 gtk_widget_show (label);
2776 gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum), label);
2779 label = gtk_label_new (_("dialog preferances will go here"));
2780 gtk_widget_show (label);
2781 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
2783 /* end of dialog guts */
2786 button = gtk_button_new_with_label (_("OK"));
2787 // gtk_signal_connect (GTK_OBJECT (button), "clicked",
2788 // (GtkSignalFunc) gtk_file_selection_rename_file_confirmed,
2790 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2791 (GtkSignalFunc) gtk_file_selection_file_mode_confirmed,
2793 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2794 button, TRUE, TRUE, 0);
2795 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2796 gtk_widget_show(button);
2798 button = gtk_button_new_with_label (_("Cancel"));
2799 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2800 (GtkSignalFunc) gtk_widget_destroy,
2802 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
2803 button, TRUE, TRUE, 0);
2804 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2805 gtk_widget_grab_default(button);
2806 gtk_widget_show (button);
2809 gtk_widget_show (dialog);
2813 gtk_file_selection_key_press (GtkWidget *widget,
2818 GtkFileSelection *fs;
2821 g_return_val_if_fail (widget != NULL, FALSE);
2822 g_return_val_if_fail (event != NULL, FALSE);
2824 fs = GTK_FILE_SELECTION (user_data);
2826 if (fs->saved_entry)
2828 gtk_clist_unselect_all ((GtkCList *) (fs->dir_list));
2829 gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry);
2830 g_free (fs->saved_entry);
2831 fs->saved_entry = NULL;
2833 if (event->keyval == GDK_Tab)
2835 text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry));
2837 text = g_strdup (text);
2839 gtk_file_selection_populate (fs, text, TRUE);
2843 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
2854 gtk_file_selection_home_button (GtkWidget *widget, gpointer data){
2857 GtkFileSelection *fs=data;
2859 list = fs->next_history;
2862 g_free (list->data);
2865 g_list_free (fs->next_history);
2866 fs->next_history = NULL;
2868 gtk_file_selection_populate (fs,"~/",FALSE);
2872 gtk_file_selection_bookmark_button (GtkWidget *widget,
2873 GtkFileSelection *fs)
2876 g_return_if_fail (fs != NULL);
2877 g_return_if_fail (GTK_FILE_SELECTION (fs));
2879 gtk_menu_popup (GTK_MENU (fs->bookmark_menu), NULL, NULL, NULL, NULL,
2885 gtk_file_selection_up_button (GtkWidget *widget, gpointer data){
2886 GtkFileSelection *fs = data;
2889 g_return_if_fail (fs != NULL);
2890 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2892 list = fs->next_history;
2895 g_free (list->data);
2898 g_list_free (fs->next_history);
2899 fs->next_history = NULL;
2901 gtk_file_selection_populate (fs, "../", FALSE); /*change directories. */
2906 gtk_file_selection_prev_button (GtkWidget *widget, gpointer data){
2907 GtkFileSelection *fs = data;
2912 g_return_if_fail (fs != NULL);
2913 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2915 list = fs->prev_history;
2917 if (list && g_list_length(list) > 1)
2919 first = list; /* get first element */
2920 list = list->next; /* pop off current directory */
2922 list->prev = NULL; /* make this the new head. */
2924 fs->prev_history = list; /* update prev_history list */
2925 fs->next_history = g_list_prepend(fs->next_history,first->data); /* put it on next_history */
2927 first->next = NULL; /* orphan the old first node */
2928 g_list_free (first); /* free the node (data is now in use by next_history) */
2932 path = g_malloc(strlen(list->data)+4); /* plenty of space */
2933 strcpy(path,list->data); /* get the 2nd path in the history */
2934 strcat(path,"/"); /* append a '/' */
2935 gtk_file_selection_populate (fs, path, FALSE); /* change directories. */
2941 gtk_file_selection_next_button (GtkWidget *widget, gpointer data){
2942 GtkFileSelection *fs = data;
2947 g_return_if_fail (fs != NULL);
2948 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2950 list = fs->next_history;
2952 if (list && g_list_length(list) > 0)
2954 first = list; /*get first element*/
2955 list = list->next; /*pop off current directory*/
2960 fs->next_history = list; /*update prev_history list*/
2962 path = g_malloc(strlen(first->data)+4); /*plenty of space*/
2963 strcpy(path,first->data);
2964 strcat(path,"/"); /*append a / */
2965 gtk_file_selection_populate (fs, path, FALSE); /*change directories.*/
2968 first->next = NULL; /* orphan the old first node */
2969 g_list_free (first); /* free the node (data is now in use by next_history) */
2975 gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data){
2976 GtkFileSelection *fs = data;
2978 g_return_if_fail (fs != NULL);
2979 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
2981 gtk_file_selection_populate (fs,"",FALSE);
2985 gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data){
2986 GtkFileSelection *fs = data;
2991 fs->mask = g_strdup(gtk_entry_get_text (GTK_ENTRY(GTK_COMBO(fs->mask_entry)->entry)));
2993 if (strlen(fs->mask) == 0)
2999 gtk_file_selection_refresh_button (widget,data);
3002 static gint gtk_file_selection_files_list_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data){
3003 GtkFileSelection *fs=data;
3007 // g_print("Key event: %d\n",event->keyval);
3008 //we need some sort of timeout.
3010 //if the key is a normal character then
3011 //add to our saved_entry1
3012 //if it's backspace then remove one character
3013 //otherwise let it through (and erase our buffer.
3015 if(event->keyval > GDK_space && event->keyval <= GDK_Korean_Won) {
3017 key[0]=event->keyval;
3018 saved=fs->saved_entry1;
3019 if(fs->saved_entry1){
3020 fs->saved_entry1=g_strconcat(saved,key,NULL);
3023 fs->saved_entry1=g_strdup(key);
3025 g_print("complete: %s\n",fs->saved_entry1);
3026 /*gtk_label_set_text(GTK_LABEL(fs->completion_label), fs->saved_entry1); */
3028 saved=g_strdup(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry)));
3029 gtk_file_selection_complete(fs,fs->saved_entry1);
3030 gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),saved);
3032 }else if (event->keyval == GDK_BackSpace) {
3033 if(strlen(fs->saved_entry1)){
3034 fs->saved_entry1[strlen(fs->saved_entry1)-1]=0;
3035 g_print("complete: %s\n",fs->saved_entry1);
3036 /*gtk_label_set_text(GTK_LABEL(fs->completion_label),fs->saved_entry1); */
3037 saved=g_strdup(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry)));
3038 gtk_file_selection_complete(fs,fs->saved_entry1);
3039 gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),saved);
3042 }else if (event->keyval == GDK_Tab) {
3043 saved=g_strdup(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry)));
3044 gtk_file_selection_populate(fs,fs->saved_entry1,TRUE);
3045 g_free(fs->saved_entry1);
3046 fs->saved_entry1=gtk_entry_get_text(GTK_ENTRY(fs->selection_entry));
3047 gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),saved);
3050 g_print("complete: %s\n",fs->saved_entry1);
3051 /* gtk_label_set_text(GTK_LABEL(fs->completion_label),fs->saved_entry1);*/
3053 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
3055 if(fs->saved_entry1){
3056 g_free(fs->saved_entry1);
3057 fs->saved_entry1=NULL;
3059 /* gtk_label_set_text(GTK_LABEL(fs->completion_label)," "); */
3066 static gint gtk_file_selection_mask_entry_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data)
3068 GtkEntry *entry=(GtkEntry *)widget;
3069 GtkFileSelection *fs=data;
3071 g_return_val_if_fail (fs != NULL,FALSE);
3072 g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs),FALSE);
3075 if (event->keyval == GDK_Return || event->keyval == GDK_Tab)
3080 fs->mask=g_strdup(gtk_entry_get_text(entry));
3081 gtk_file_selection_refresh_button(widget,fs);
3083 if (event->keyval == GDK_Return)
3084 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
3093 static gint gtk_file_selection_mask_entry_button_callback (GtkWidget *widget, GdkEventButton *event, gpointer data)
3095 GtkFileSelection *fs = data;
3100 fs->mask=g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(fs->mask_entry)->entry)));
3101 gtk_file_selection_refresh_button(widget,fs);
3107 static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget,
3112 g_print("Key pressed! \n");
3118 static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist,
3119 GdkEventButton *event,
3123 GtkFileSelection *fs = user_data;
3127 list = fs->next_history;
3130 g_free (list->data);
3133 g_list_free (fs->next_history);
3134 fs->next_history = NULL;
3136 path = g_malloc(strlen(gtk_entry_get_text(GTK_ENTRY (((GtkCombo *)fs->history_combo)->entry)))+4);
3137 strcpy (path,gtk_entry_get_text(GTK_ENTRY( ((GtkCombo *)fs->history_combo)->entry)));
3140 gtk_file_selection_populate (fs,path,TRUE);
3148 gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data)
3150 GtkEntry *entry=(GtkEntry *)widget;
3151 GtkFileSelection *fs=data;
3155 g_return_val_if_fail (fs != NULL,FALSE);
3156 g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs),FALSE);
3159 if (event->keyval == GDK_Return)
3161 list = fs->next_history;
3164 g_free (list->data);
3167 g_list_free (fs->next_history);
3168 fs->next_history = NULL;
3170 path = g_malloc(strlen(gtk_entry_get_text(entry))+4);
3171 strcpy (path,gtk_entry_get_text(entry));
3173 gtk_file_selection_populate (fs,path,TRUE);
3175 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
3186 static void gtk_file_selection_bookmark_callback (GtkWidget *widget, gpointer data)
3188 GtkFileSelection *fs = data;
3189 BookmarkMenuStruct *item;
3192 g_return_if_fail (fs != NULL);
3193 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
3195 //g_print ("Callback\n");
3196 list = fs->bookmark_list;
3199 if (item->menu_item == widget) {
3200 if(strcmp(item->path,"./")) {
3201 gtk_file_selection_populate (fs, item->path, FALSE);
3210 gtk_file_selection_update_history_menu (GtkFileSelection *fs,
3211 gchar *current_directory)
3215 g_return_if_fail (fs != NULL);
3216 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
3217 g_return_if_fail (current_directory != NULL);
3219 current_dir = g_strdup (current_directory);
3221 if(fs->prev_history)
3223 if (strcmp((fs->prev_history)->data,current_dir))
3224 { /*if this item isn't on the top of the list */
3225 fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir));
3228 fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir));
3231 gtk_combo_set_popdown_strings (GTK_COMBO (fs->history_combo),fs->prev_history);
3233 g_free (current_dir);
3237 gtk_file_selection_file_button (GtkWidget *widget,
3240 GdkEventButton *bevent,
3243 GtkFileSelection *fs = NULL;
3244 gchar *filename, *temp = NULL;
3246 g_return_if_fail (GTK_IS_CLIST (widget));
3249 g_return_if_fail (fs != NULL);
3250 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
3252 gtk_clist_get_text (GTK_CLIST (fs->file_list), row, 0, &temp);
3253 filename = g_strdup (temp);
3257 if (fs->saved_entry)
3259 gtk_clist_unselect_all ((GtkCList *) (fs->dir_list));
3260 gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry);
3261 g_free (fs->saved_entry);
3262 fs->saved_entry = NULL;
3264 if(fs->saved_entry1){
3265 g_free(fs->saved_entry1);
3266 fs->saved_entry1=NULL;
3268 /* gtk_label_set_text(GTK_LABEL(fs->completion_label)," "); */
3272 switch (bevent->type)
3274 case GDK_2BUTTON_PRESS:
3275 gtk_button_clicked (GTK_BUTTON (fs->ok_button));
3280 if (bevent->button && GDK_BUTTON2_MASK)
3282 g_print("Right click! -- %d\n",bevent->button);
3288 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
3293 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
3300 gtk_file_selection_dir_button (GtkWidget *widget,
3303 GdkEventButton *bevent,
3307 GtkFileSelection *fs = NULL;
3308 gchar *filename, *temp = NULL;
3310 g_return_if_fail (GTK_IS_CLIST (widget));
3312 fs = GTK_FILE_SELECTION (user_data);
3313 g_return_if_fail (fs != NULL);
3314 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
3316 gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp);
3317 filename = g_strdup (temp);
3322 switch (bevent->type)
3324 case GDK_2BUTTON_PRESS:
3325 list = fs->next_history;
3328 g_free (list->data);
3331 g_list_free (fs->next_history);
3332 fs->next_history = NULL;
3334 gtk_file_selection_populate (fs, filename, FALSE);
3335 gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry);
3336 g_free (fs->saved_entry);
3337 fs->saved_entry = NULL;
3341 /* here we need to add the "filename" to the beginning of what's already
3342 in the entry. Save what's in the entry, then restore it on the double click
3344 if (fs->saved_entry) g_free (fs->saved_entry);
3345 fs->saved_entry=g_strdup(gtk_entry_get_text(GTK_ENTRY (fs->selection_entry)));
3347 temp=g_strconcat(filename,fs->saved_entry,NULL);
3348 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), temp);
3354 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename);
3361 gtk_file_selection_undir_button (GtkWidget *widget,
3364 GdkEventButton *bevent,
3367 GtkFileSelection *fs = NULL;
3368 gchar *filename, *temp = NULL;
3370 g_return_if_fail (GTK_IS_CLIST (widget));
3372 fs = GTK_FILE_SELECTION (user_data);
3373 g_return_if_fail (fs != NULL);
3374 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
3376 gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp);
3377 filename = g_strdup (temp);
3382 switch (bevent->type)
3385 /* here we need to add the "filename" to the beginning of what's already
3386 in the entry. Save what's in the entry, then restore it on the double click
3388 if (fs->saved_entry)
3390 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry),fs->saved_entry);
3391 g_free (fs->saved_entry);
3392 fs->saved_entry = NULL;
3397 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); //?????
3404 gtk_file_selection_populate (GtkFileSelection *fs,
3408 CompletionState *cmpl_state;
3409 PossibleCompletion* poss;
3412 gchar* rem_path = rel_path;
3415 gint did_recurse = FALSE;
3416 gint possible_count = 0;
3417 gint selection_index = -1;
3418 gint file_list_width;
3419 gint dir_list_width;
3421 g_return_if_fail (fs != NULL);
3422 g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
3424 cmpl_state = (CompletionState*) fs->cmpl_state;
3425 poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state);
3427 if (!cmpl_state_okay (cmpl_state))
3429 /* Something went wrong. */
3430 gtk_file_selection_abort (fs);
3434 g_assert (cmpl_state->reference_dir);
3436 gtk_clist_freeze (GTK_CLIST (fs->dir_list));
3437 gtk_clist_clear (GTK_CLIST (fs->dir_list));
3438 gtk_clist_freeze (GTK_CLIST (fs->file_list));
3439 gtk_clist_clear (GTK_CLIST (fs->file_list));
3441 /* Set the dir_list to include ./ and ../ */
3442 /* Actually, no let's not.
3445 row = gtk_clist_append (GTK_CLIST (fs->dir_list), text);
3448 text[0] = "../"; //Do we need ..?
3449 row = gtk_clist_append (GTK_CLIST (fs->dir_list), text);
3451 /*reset the max widths of the lists*/
3452 dir_list_width = gdk_string_width(fs->dir_list->style->font,"../");
3453 gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0,dir_list_width);
3454 file_list_width = 1;
3455 gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,file_list_width);
3459 if (cmpl_is_a_completion (poss))
3461 possible_count += 1;
3463 filename = cmpl_this_completion (poss);
3467 if (cmpl_is_directory (poss))
3469 if (strcmp (filename, "./") != 0 &&
3470 strcmp (filename, "../") != 0)
3472 int width = gdk_string_width(fs->dir_list->style->font,
3474 row = gtk_clist_append (GTK_CLIST (fs->dir_list), text);
3475 if(width > dir_list_width)
3477 dir_list_width = width;
3478 gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0,
3487 if (gtk_file_selection_match_mask(filename,fs->mask))
3489 int width = gdk_string_width(fs->file_list->style->font,
3491 row = gtk_clist_append (GTK_CLIST (fs->file_list), text);
3492 if(width > file_list_width)
3494 file_list_width = width;
3495 gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,
3502 int width = gdk_string_width(fs->file_list->style->font,
3504 row = gtk_clist_append (GTK_CLIST (fs->file_list), text);
3505 if(width > file_list_width)
3507 file_list_width = width;
3508 gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,
3515 poss = cmpl_next_completion (cmpl_state);
3518 gtk_clist_thaw (GTK_CLIST (fs->dir_list));
3519 gtk_clist_thaw (GTK_CLIST (fs->file_list));
3521 /* File lists are set. */
3523 g_assert (cmpl_state->reference_dir);
3528 /* User is trying to complete filenames, so advance the user's input
3529 * string to the updated_text, which is the common leading substring
3530 * of all possible completions, and if its a directory attempt
3531 * attempt completions in it. */
3533 if (cmpl_updated_text (cmpl_state)[0])
3536 if (cmpl_updated_dir (cmpl_state))
3538 gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state));
3542 gtk_file_selection_populate (fs, dir_name, TRUE);
3548 if (fs->selection_entry)
3549 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry),
3550 cmpl_updated_text (cmpl_state));
3555 selection_index = cmpl_last_valid_char (cmpl_state) -
3556 (strlen (rel_path) - strlen (rem_path));
3557 if (fs->selection_entry)
3558 gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path);
3563 if (fs->selection_entry)
3564 /* Here we need to take the old filename and keep it!*/
3565 /*gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");*/
3571 if (fs->selection_entry)
3572 gtk_entry_set_position (GTK_ENTRY (fs->selection_entry), selection_index);
3574 if (fs->selection_entry)
3576 sel_text = g_strconcat (_("Selection: "),
3577 cmpl_reference_position (cmpl_state),
3581 gtk_label_set_text (GTK_LABEL (fs->selection_text), sel_text);
3586 gtk_file_selection_update_history_menu (fs, cmpl_reference_position (cmpl_state));
3592 gtk_file_selection_abort (GtkFileSelection *fs)
3596 sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno));
3598 /* BEEP gdk_beep(); */
3601 if (fs->selection_entry)
3602 gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf);
3606 /**********************************************************************/
3607 /* External Interface */
3608 /**********************************************************************/
3610 /* The four completion state selectors
3613 cmpl_updated_text (CompletionState* cmpl_state)
3615 return cmpl_state->updated_text;
3619 cmpl_updated_dir (CompletionState* cmpl_state)
3621 return cmpl_state->re_complete;
3625 cmpl_reference_position (CompletionState* cmpl_state)
3627 return cmpl_state->reference_dir->fullname;
3631 cmpl_last_valid_char (CompletionState* cmpl_state)
3633 return cmpl_state->last_valid_char;
3637 cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state)
3639 static char nothing[2] = "";
3641 if (!cmpl_state_okay (cmpl_state))
3645 else if (text[0] == '/')
3647 strcpy (cmpl_state->updated_text, text);
3649 else if (text[0] == '~')
3654 dir = open_user_dir (text, cmpl_state);
3658 /* spencer says just return ~something, so
3659 * for now just do it. */
3660 strcpy (cmpl_state->updated_text, text);
3665 strcpy (cmpl_state->updated_text, dir->fullname);
3667 slash = strchr (text, '/');
3670 strcat (cmpl_state->updated_text, slash);
3675 strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname);
3676 if (strcmp (cmpl_state->reference_dir->fullname, "/") != 0)
3677 strcat (cmpl_state->updated_text, "/");
3678 strcat (cmpl_state->updated_text, text);
3681 return cmpl_state->updated_text;
3684 /* The three completion selectors
3687 cmpl_this_completion (PossibleCompletion* pc)
3693 cmpl_is_directory (PossibleCompletion* pc)
3695 return pc->is_directory;
3699 cmpl_is_a_completion (PossibleCompletion* pc)
3701 return pc->is_a_completion;
3704 /**********************************************************************/
3705 /* Construction, deletion */
3706 /**********************************************************************/
3708 static CompletionState*
3709 cmpl_init_state (void)
3711 gchar getcwd_buf[2*MAXPATHLEN];
3712 CompletionState *new_state;
3714 new_state = g_new (CompletionState, 1);
3716 /* We don't use getcwd() on SUNOS, because, it does a popen("pwd")
3717 * and, if that wasn't bad enough, hangs in doing so.
3719 #if defined(sun) && !defined(__SVR4)
3720 if (!getwd (getcwd_buf))
3722 if (!getcwd (getcwd_buf, MAXPATHLEN))
3725 /* Oh joy, we can't get the current directory. Um..., we should have
3726 * a root directory, right? Right? (Probably not portable to non-Unix)
3728 strcpy (getcwd_buf, "/");
3733 new_state->reference_dir = NULL;
3734 new_state->completion_dir = NULL;
3735 new_state->active_completion_dir = NULL;
3736 new_state->directory_storage = NULL;
3737 new_state->directory_sent_storage = NULL;
3738 new_state->last_valid_char = 0;
3739 new_state->updated_text = g_new (gchar, MAXPATHLEN);
3740 new_state->updated_text_alloc = MAXPATHLEN;
3741 new_state->the_completion.text = g_new (gchar, MAXPATHLEN);
3742 new_state->the_completion.text_alloc = MAXPATHLEN;
3743 new_state->user_dir_name_buffer = NULL;
3744 new_state->user_directories = NULL;
3746 new_state->reference_dir = open_dir (getcwd_buf, new_state);
3748 if (!new_state->reference_dir)
3750 /* Directories changing from underneath us, grumble */
3751 strcpy (getcwd_buf, "/");
3759 cmpl_free_dir_list(GList* dp0)
3764 free_dir (dp->data);
3772 cmpl_free_dir_sent_list(GList* dp0)
3777 free_dir_sent (dp->data);
3785 cmpl_free_state (CompletionState* cmpl_state)
3787 cmpl_free_dir_list (cmpl_state->directory_storage);
3788 cmpl_free_dir_sent_list (cmpl_state->directory_sent_storage);
3790 if (cmpl_state->user_dir_name_buffer)
3791 g_free (cmpl_state->user_dir_name_buffer);
3792 if (cmpl_state->user_directories)
3793 g_free (cmpl_state->user_directories);
3794 if (cmpl_state->the_completion.text)
3795 g_free (cmpl_state->the_completion.text);
3796 if (cmpl_state->updated_text)
3797 g_free (cmpl_state->updated_text);
3799 g_free (cmpl_state);
3803 free_dir(CompletionDir* dir)
3805 g_free(dir->fullname);
3810 free_dir_sent(CompletionDirSent* sent)
3812 g_free(sent->name_buffer);
3813 g_free(sent->entries);
3818 prune_memory_usage(CompletionState *cmpl_state)
3820 GList* cdsl = cmpl_state->directory_sent_storage;
3821 GList* cdl = cmpl_state->directory_storage;
3825 for(; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1)
3829 cmpl_free_dir_sent_list(cdsl->next);
3833 cmpl_state->directory_storage = NULL;
3835 if (cdl->data == cmpl_state->reference_dir)
3836 cmpl_state->directory_storage = g_list_prepend(NULL, cdl->data);
3838 free_dir (cdl->data);
3845 /**********************************************************************/
3846 /* The main entrances. */
3847 /**********************************************************************/
3849 static PossibleCompletion*
3850 cmpl_completion_matches (gchar* text_to_complete,
3851 gchar** remaining_text,
3852 CompletionState* cmpl_state)
3855 PossibleCompletion *poss;
3857 prune_memory_usage(cmpl_state);
3859 g_assert (text_to_complete != NULL);
3861 cmpl_state->user_completion_index = -1;
3862 cmpl_state->last_completion_text = text_to_complete;
3863 cmpl_state->the_completion.text[0] = 0;
3864 cmpl_state->last_valid_char = 0;
3865 cmpl_state->updated_text_len = -1;
3866 cmpl_state->updated_text[0] = 0;
3867 cmpl_state->re_complete = FALSE;
3869 first_slash = strchr (text_to_complete, '/');
3871 if (text_to_complete[0] == '~' && !first_slash)
3873 /* Text starts with ~ and there is no slash, show all the
3874 * home directory completions.
3876 poss = attempt_homedir_completion (text_to_complete, cmpl_state);
3878 update_cmpl(poss, cmpl_state);
3883 cmpl_state->reference_dir =
3884 open_ref_dir (text_to_complete, remaining_text, cmpl_state);
3886 if(!cmpl_state->reference_dir)
3889 cmpl_state->completion_dir =
3890 find_completion_dir (*remaining_text, remaining_text, cmpl_state);
3892 cmpl_state->last_valid_char = *remaining_text - text_to_complete;
3894 if(!cmpl_state->completion_dir)
3897 cmpl_state->completion_dir->cmpl_index = -1;
3898 cmpl_state->completion_dir->cmpl_parent = NULL;
3899 cmpl_state->completion_dir->cmpl_text = *remaining_text;
3901 cmpl_state->active_completion_dir = cmpl_state->completion_dir;
3903 cmpl_state->reference_dir = cmpl_state->completion_dir;
3905 poss = attempt_file_completion(cmpl_state);
3907 update_cmpl(poss, cmpl_state);
3912 static PossibleCompletion*
3913 cmpl_next_completion (CompletionState* cmpl_state)
3915 PossibleCompletion* poss = NULL;
3917 cmpl_state->the_completion.text[0] = 0;
3919 if(cmpl_state->user_completion_index >= 0)
3920 poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state);
3922 poss = attempt_file_completion(cmpl_state);
3924 update_cmpl(poss, cmpl_state);
3929 /**********************************************************************/
3930 /* Directory Operations */
3931 /**********************************************************************/
3933 /* Open the directory where completion will begin from, if possible. */
3934 static CompletionDir*
3935 open_ref_dir(gchar* text_to_complete,
3936 gchar** remaining_text,
3937 CompletionState* cmpl_state)
3940 CompletionDir *new_dir;
3942 first_slash = strchr(text_to_complete, '/');
3944 if (text_to_complete[0] == '~')
3946 new_dir = open_user_dir(text_to_complete, cmpl_state);
3951 *remaining_text = first_slash + 1;
3953 *remaining_text = text_to_complete + strlen(text_to_complete);
3960 else if (text_to_complete[0] == '/' || !cmpl_state->reference_dir)
3962 gchar *tmp = g_strdup(text_to_complete);
3966 while (*p && *p != '*' && *p != '?')
3970 p = strrchr(tmp, '/');
3978 new_dir = open_dir(tmp, cmpl_state);
3981 *remaining_text = text_to_complete +
3982 ((p == tmp + 1) ? (p - tmp) : (p + 1 - tmp));
3986 /* If no possible candidates, use the cwd */
3987 gchar *curdir = g_get_current_dir ();
3989 new_dir = open_dir(curdir, cmpl_state);
3992 *remaining_text = text_to_complete;
4001 *remaining_text = text_to_complete;
4003 new_dir = open_dir(cmpl_state->reference_dir->fullname, cmpl_state);
4008 new_dir->cmpl_index = -1;
4009 new_dir->cmpl_parent = NULL;
4015 /* open a directory by user name */
4016 static CompletionDir*
4017 open_user_dir(gchar* text_to_complete,
4018 CompletionState *cmpl_state)
4023 g_assert(text_to_complete && text_to_complete[0] == '~');
4025 first_slash = strchr(text_to_complete, '/');
4028 cmp_len = first_slash - text_to_complete - 1;
4030 cmp_len = strlen(text_to_complete + 1);
4035 gchar *homedir = g_get_home_dir ();
4038 return open_dir(homedir, cmpl_state);
4045 char* copy = g_new(char, cmp_len + 1);
4047 strncpy(copy, text_to_complete + 1, cmp_len);
4049 pwd = getpwnam(copy);
4057 return open_dir(pwd->pw_dir, cmpl_state);
4061 /* open a directory relative the the current relative directory */
4062 static CompletionDir*
4063 open_relative_dir(gchar* dir_name,
4065 CompletionState *cmpl_state)
4067 gchar path_buf[2*MAXPATHLEN];
4069 if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN)
4071 cmpl_errno = CMPL_ERRNO_TOO_LONG;
4075 strcpy(path_buf, dir->fullname);
4077 if(dir->fullname_len > 1)
4079 path_buf[dir->fullname_len] = '/';
4080 strcpy(path_buf + dir->fullname_len + 1, dir_name);
4084 strcpy(path_buf + dir->fullname_len, dir_name);
4087 return open_dir(path_buf, cmpl_state);
4090 /* after the cache lookup fails, really open a new directory */
4091 static CompletionDirSent*
4092 open_new_dir(gchar* dir_name, struct stat* sbuf, gboolean stat_subdirs)
4094 CompletionDirSent* sent;
4097 struct dirent *dirent_ptr;
4098 gint buffer_size = 0;
4099 gint entry_count = 0;
4101 struct stat ent_sbuf;
4102 char path_buf[MAXPATHLEN*2];
4105 sent = g_new(CompletionDirSent, 1);
4106 sent->mtime = sbuf->st_mtime;
4107 sent->inode = sbuf->st_ino;
4108 sent->device = sbuf->st_dev;
4110 path_buf_len = strlen(dir_name);
4112 if (path_buf_len > MAXPATHLEN)
4114 cmpl_errno = CMPL_ERRNO_TOO_LONG;
4118 strcpy(path_buf, dir_name);
4120 directory = opendir(dir_name);
4128 while((dirent_ptr = readdir(directory)) != NULL)
4130 int entry_len = strlen(dirent_ptr->d_name);
4131 buffer_size += entry_len + 1;
4134 if(path_buf_len + entry_len + 2 >= MAXPATHLEN)
4136 cmpl_errno = CMPL_ERRNO_TOO_LONG;
4137 closedir(directory);
4142 sent->name_buffer = g_new(gchar, buffer_size);
4143 sent->entries = g_new(CompletionDirEntry, entry_count);
4144 sent->entry_count = entry_count;
4146 buffer_ptr = sent->name_buffer;
4148 rewinddir(directory);
4150 for(i = 0; i < entry_count; i += 1)
4152 dirent_ptr = readdir(directory);
4157 closedir(directory);
4161 strcpy(buffer_ptr, dirent_ptr->d_name);
4162 sent->entries[i].entry_name = buffer_ptr;
4163 buffer_ptr += strlen(dirent_ptr->d_name);
4167 path_buf[path_buf_len] = '/';
4168 strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name);
4172 if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode))
4173 sent->entries[i].is_dir = 1;
4175 /* stat may fail, and we don't mind, since it could be a
4176 * dangling symlink. */
4177 sent->entries[i].is_dir = 0;
4180 sent->entries[i].is_dir = 1;
4183 qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir);
4185 closedir(directory);
4191 check_dir(gchar *dir_name, struct stat *result, gboolean *stat_subdirs)
4193 /* A list of directories that we know only contain other directories.
4194 * Trying to stat every file in these directories would be very
4201 struct stat statbuf;
4202 } no_stat_dirs[] = {
4203 { "/afs", FALSE, { 0 } },
4204 { "/net", FALSE, { 0 } }
4207 static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]);
4208 static gboolean initialized = FALSE;
4215 for (i = 0; i < n_no_stat_dirs; i++)
4217 if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0)
4218 no_stat_dirs[i].present = TRUE;
4222 if(stat(dir_name, result) < 0)
4228 *stat_subdirs = TRUE;
4229 for (i=0; i<n_no_stat_dirs; i++)
4231 if (no_stat_dirs[i].present &&
4232 (no_stat_dirs[i].statbuf.st_dev == result->st_dev) &&
4233 (no_stat_dirs[i].statbuf.st_ino == result->st_ino))
4235 *stat_subdirs = FALSE;
4243 /* open a directory by absolute pathname */
4244 static CompletionDir*
4245 open_dir(gchar* dir_name, CompletionState* cmpl_state)
4248 gboolean stat_subdirs;
4249 CompletionDirSent *sent;
4252 if (!check_dir (dir_name, &sbuf, &stat_subdirs))
4255 cdsl = cmpl_state->directory_sent_storage;
4261 if(sent->inode == sbuf.st_ino &&
4262 sent->mtime == sbuf.st_mtime &&
4263 sent->device == sbuf.st_dev)
4264 return attach_dir(sent, dir_name, cmpl_state);
4269 sent = open_new_dir(dir_name, &sbuf, stat_subdirs);
4272 cmpl_state->directory_sent_storage =
4273 g_list_prepend(cmpl_state->directory_sent_storage, sent);
4275 return attach_dir(sent, dir_name, cmpl_state);
4281 static CompletionDir*
4282 attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state)
4284 CompletionDir* new_dir;
4286 new_dir = g_new(CompletionDir, 1);
4288 cmpl_state->directory_storage =
4289 g_list_prepend(cmpl_state->directory_storage, new_dir);
4291 new_dir->sent = sent;
4292 new_dir->fullname = g_strdup(dir_name);
4293 new_dir->fullname_len = strlen(dir_name);
4299 correct_dir_fullname(CompletionDir* cmpl_dir)
4301 gint length = strlen(cmpl_dir->fullname);
4304 if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0)
4308 strcpy(cmpl_dir->fullname, "/");
4309 cmpl_dir->fullname_len = 1;
4312 cmpl_dir->fullname[length - 2] = 0;
4315 else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0)
4316 cmpl_dir->fullname[length - 2] = 0;
4317 else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0)
4321 strcpy(cmpl_dir->fullname, "/");
4322 cmpl_dir->fullname_len = 1;
4326 if(stat(cmpl_dir->fullname, &sbuf) < 0)
4332 cmpl_dir->fullname[length - 2] = 0;
4334 if(!correct_parent(cmpl_dir, &sbuf))
4337 else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0)
4341 strcpy(cmpl_dir->fullname, "/");
4342 cmpl_dir->fullname_len = 1;
4346 if(stat(cmpl_dir->fullname, &sbuf) < 0)
4352 cmpl_dir->fullname[length - 3] = 0;
4354 if(!correct_parent(cmpl_dir, &sbuf))
4358 cmpl_dir->fullname_len = strlen(cmpl_dir->fullname);
4364 correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf)
4371 last_slash = strrchr(cmpl_dir->fullname, '/');
4373 g_assert(last_slash);
4375 if(last_slash != cmpl_dir->fullname)
4376 { /* last_slash[0] = 0; */ }
4383 if (stat(cmpl_dir->fullname, &parbuf) < 0)
4389 if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev)
4390 /* it wasn't a link */
4396 last_slash[0] = '/'; */
4398 /* it was a link, have to figure it out the hard way */
4400 new_name = find_parent_dir_fullname(cmpl_dir->fullname);
4405 g_free(cmpl_dir->fullname);
4407 cmpl_dir->fullname = new_name;
4413 find_parent_dir_fullname(gchar* dirname)
4415 gchar buffer[MAXPATHLEN];
4416 gchar buffer2[MAXPATHLEN];
4418 #if defined(sun) && !defined(__SVR4)
4421 if(!getcwd(buffer, MAXPATHLEN))
4428 if(chdir(dirname) != 0 || chdir("..") != 0)
4434 #if defined(sun) && !defined(__SVR4)
4437 if(!getcwd(buffer2, MAXPATHLEN))
4446 if(chdir(buffer) != 0)
4452 return g_strdup(buffer2);
4455 /**********************************************************************/
4456 /* Completion Operations */
4457 /**********************************************************************/
4459 static PossibleCompletion*
4460 attempt_homedir_completion(gchar* text_to_complete,
4461 CompletionState *cmpl_state)
4465 if (!cmpl_state->user_dir_name_buffer &&
4466 !get_pwdb(cmpl_state))
4468 length = strlen(text_to_complete) - 1;
4470 cmpl_state->user_completion_index += 1;
4472 while(cmpl_state->user_completion_index < cmpl_state->user_directories_len)
4474 index = first_diff_index(text_to_complete + 1,
4475 cmpl_state->user_directories
4476 [cmpl_state->user_completion_index].login);
4483 if(cmpl_state->last_valid_char < (index + 1))
4484 cmpl_state->last_valid_char = index + 1;
4485 cmpl_state->user_completion_index += 1;
4489 cmpl_state->the_completion.is_a_completion = 1;
4490 cmpl_state->the_completion.is_directory = 1;
4492 append_completion_text("~", cmpl_state);
4494 append_completion_text(cmpl_state->
4495 user_directories[cmpl_state->user_completion_index].login,
4498 return append_completion_text("/", cmpl_state);
4501 if(text_to_complete[1] ||
4502 cmpl_state->user_completion_index > cmpl_state->user_directories_len)
4504 cmpl_state->user_completion_index = -1;
4509 cmpl_state->user_completion_index += 1;
4510 cmpl_state->the_completion.is_a_completion = 1;
4511 cmpl_state->the_completion.is_directory = 1;
4513 return append_completion_text("~/", cmpl_state);
4517 /* returns the index (>= 0) of the first differing character,
4518 * PATTERN_MATCH if the completion matches */
4520 first_diff_index(gchar* pat, gchar* text)
4524 while(*pat && *text && *text == *pat)
4534 return PATTERN_MATCH;
4537 static PossibleCompletion*
4538 append_completion_text(gchar* text, CompletionState* cmpl_state)
4542 if(!cmpl_state->the_completion.text)
4545 len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1;
4547 if(cmpl_state->the_completion.text_alloc > len)
4549 strcat(cmpl_state->the_completion.text, text);
4550 return &cmpl_state->the_completion;
4553 while(i < len) { i <<= 1; }
4555 cmpl_state->the_completion.text_alloc = i;
4557 cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i);
4559 if(!cmpl_state->the_completion.text)
4563 strcat(cmpl_state->the_completion.text, text);
4564 return &cmpl_state->the_completion;
4568 static CompletionDir*
4569 find_completion_dir(gchar* text_to_complete,
4570 gchar** remaining_text,
4571 CompletionState* cmpl_state)
4573 gchar* first_slash = strchr(text_to_complete, '/');
4574 CompletionDir* dir = cmpl_state->reference_dir;
4575 CompletionDir* next;
4576 *remaining_text = text_to_complete;
4580 gint len = first_slash - *remaining_text;
4582 gchar *found_name = NULL; /* Quiet gcc */
4584 gchar* pat_buf = g_new (gchar, len + 1);
4586 strncpy(pat_buf, *remaining_text, len);
4589 for(i = 0; i < dir->sent->entry_count; i += 1)
4591 if(dir->sent->entries[i].is_dir &&
4592 fnmatch(pat_buf, dir->sent->entries[i].entry_name,
4593 FNMATCH_FLAGS)!= FNM_NOMATCH)
4603 found_name = dir->sent->entries[i].entry_name;
4610 /* Perhaps we are trying to open an automount directory */
4611 found_name = pat_buf;
4614 next = open_relative_dir(found_name, dir, cmpl_state);
4622 next->cmpl_parent = dir;
4626 if(!correct_dir_fullname(dir))
4632 *remaining_text = first_slash + 1;
4633 first_slash = strchr(*remaining_text, '/');
4642 update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state)
4646 if(!poss || !cmpl_is_a_completion(poss))
4649 cmpl_len = strlen(cmpl_this_completion(poss));
4651 if(cmpl_state->updated_text_alloc < cmpl_len + 1)
4653 cmpl_state->updated_text =
4654 (gchar*)g_realloc(cmpl_state->updated_text,
4655 cmpl_state->updated_text_alloc);
4656 cmpl_state->updated_text_alloc = 2*cmpl_len;
4659 if(cmpl_state->updated_text_len < 0)
4661 strcpy(cmpl_state->updated_text, cmpl_this_completion(poss));
4662 cmpl_state->updated_text_len = cmpl_len;
4663 cmpl_state->re_complete = cmpl_is_directory(poss);
4665 else if(cmpl_state->updated_text_len == 0)
4667 cmpl_state->re_complete = FALSE;
4672 first_diff_index(cmpl_state->updated_text,
4673 cmpl_this_completion(poss));
4675 cmpl_state->re_complete = FALSE;
4677 if(first_diff == PATTERN_MATCH)
4680 if(first_diff > cmpl_state->updated_text_len)
4681 strcpy(cmpl_state->updated_text, cmpl_this_completion(poss));
4683 cmpl_state->updated_text_len = first_diff;
4684 cmpl_state->updated_text[first_diff] = 0;
4688 static PossibleCompletion*
4689 attempt_file_completion(CompletionState *cmpl_state)
4691 gchar *pat_buf, *first_slash;
4692 CompletionDir *dir = cmpl_state->active_completion_dir;
4694 dir->cmpl_index += 1;
4696 if(dir->cmpl_index == dir->sent->entry_count)
4698 if(dir->cmpl_parent == NULL)
4700 cmpl_state->active_completion_dir = NULL;
4706 cmpl_state->active_completion_dir = dir->cmpl_parent;
4708 return attempt_file_completion(cmpl_state);
4712 g_assert(dir->cmpl_text);
4714 first_slash = strchr(dir->cmpl_text, '/');
4718 gint len = first_slash - dir->cmpl_text;
4720 pat_buf = g_new (gchar, len + 1);
4721 strncpy(pat_buf, dir->cmpl_text, len);
4726 gint len = strlen(dir->cmpl_text);
4728 pat_buf = g_new (gchar, len + 2);
4729 strcpy(pat_buf, dir->cmpl_text);
4730 strcpy(pat_buf + len, "*");
4735 if(dir->sent->entries[dir->cmpl_index].is_dir)
4737 if(fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name,
4738 FNMATCH_FLAGS) != FNM_NOMATCH)
4740 CompletionDir* new_dir;
4742 new_dir = open_relative_dir(dir->sent->entries[dir->cmpl_index].entry_name,
4751 new_dir->cmpl_parent = dir;
4753 new_dir->cmpl_index = -1;
4754 new_dir->cmpl_text = first_slash + 1;
4756 cmpl_state->active_completion_dir = new_dir;
4759 return attempt_file_completion(cmpl_state);
4764 return attempt_file_completion(cmpl_state);
4770 return attempt_file_completion(cmpl_state);
4775 if(dir->cmpl_parent != NULL)
4777 append_completion_text(dir->fullname +
4778 strlen(cmpl_state->completion_dir->fullname) + 1,
4780 append_completion_text("/", cmpl_state);
4783 append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state);
4785 cmpl_state->the_completion.is_a_completion =
4786 (fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name,
4787 FNMATCH_FLAGS) != FNM_NOMATCH);
4789 cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir;
4790 if(dir->sent->entries[dir->cmpl_index].is_dir)
4791 append_completion_text("/", cmpl_state);
4794 return &cmpl_state->the_completion;
4800 get_pwdb(CompletionState* cmpl_state)
4802 struct passwd *pwd_ptr;
4804 gint len = 0, i, count = 0;
4806 if(cmpl_state->user_dir_name_buffer)
4810 while ((pwd_ptr = getpwent()) != NULL)
4812 len += strlen(pwd_ptr->pw_name);
4813 len += strlen(pwd_ptr->pw_dir);
4820 cmpl_state->user_dir_name_buffer = g_new(gchar, len);
4821 cmpl_state->user_directories = g_new(CompletionUserDir, count);
4822 cmpl_state->user_directories_len = count;
4824 buf_ptr = cmpl_state->user_dir_name_buffer;
4826 for(i = 0; i < count; i += 1)
4828 pwd_ptr = getpwent();
4835 strcpy(buf_ptr, pwd_ptr->pw_name);
4836 cmpl_state->user_directories[i].login = buf_ptr;
4837 buf_ptr += strlen(buf_ptr);
4839 strcpy(buf_ptr, pwd_ptr->pw_dir);
4840 cmpl_state->user_directories[i].homedir = buf_ptr;
4841 buf_ptr += strlen(buf_ptr);
4845 qsort(cmpl_state->user_directories,
4846 cmpl_state->user_directories_len,
4847 sizeof(CompletionUserDir),
4856 if(cmpl_state->user_dir_name_buffer)
4857 g_free(cmpl_state->user_dir_name_buffer);
4858 if(cmpl_state->user_directories)
4859 g_free(cmpl_state->user_directories);
4861 cmpl_state->user_dir_name_buffer = NULL;
4862 cmpl_state->user_directories = NULL;
4868 compare_user_dir(const void* a, const void* b)
4870 return strcmp((((CompletionUserDir*)a))->login,
4871 (((CompletionUserDir*)b))->login);
4875 compare_cmpl_dir(const void* a, const void* b)
4877 return strcmp((((CompletionDirEntry*)a))->entry_name,
4878 (((CompletionDirEntry*)b))->entry_name);
4882 cmpl_state_okay(CompletionState* cmpl_state)
4884 return cmpl_state && cmpl_state->reference_dir;
4888 cmpl_strerror(gint err)
4890 if(err == CMPL_ERRNO_TOO_LONG)
4891 return "Name too long";
4893 return g_strerror (err);
4896 /* This is an internally used function to create pixmaps. */
4898 create_pixmap(GtkWidget *widget, const gchar *pixmap_char)
4900 GdkPixmap *gdkpixmap;
4903 GdkColormap *colormap;
4905 colormap = gtk_widget_get_colormap (widget);
4907 gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (GTK_WIDGET(widget)->window,
4911 (gpointer) pixmap_char);
4912 if (gdkpixmap == NULL)
4914 g_warning ("Error loading pixmap: %s", pixmap_char);
4917 pixmap = gtk_pixmap_new (gdkpixmap, mask);
4918 gdk_pixmap_unref (gdkpixmap);
4919 gdk_bitmap_unref (mask);
4927 /* Get the selected filename and print it to the console */
4928 void file_ok_sel( GtkWidget *w,
4929 GtkFileSelection *fs )
4931 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
4934 void destroy( GtkWidget *widget,
4944 const gchar *masks[] = { "mp3s/playlists <*.mp3,*.m3u>",
4945 "src/hdr <*.[CcHh],*.[Cc][Cc],*.[Hh][Hh],*.cpp>",
4948 gtk_init (&argc, &argv);
4950 /* Create a new file selection widget */
4951 filew = gtk_file_selection_new ("Spiffy File Selector");
4952 // gtk_file_selection_complete(GTK_FILE_SELECTION(filew),"bob");
4954 gtk_file_selection_set_masks (GTK_FILE_SELECTION (filew), masks);
4956 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
4957 (GtkSignalFunc) destroy, &filew);
4958 /* Connect the ok_button to file_ok_sel function */
4959 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
4960 "clicked", (GtkSignalFunc) file_ok_sel, filew );
4962 /* Connect the cancel_button to destroy the widget */
4963 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
4964 (filew)->cancel_button),
4965 "clicked", (GtkSignalFunc) gtk_widget_destroy,
4966 GTK_OBJECT (filew));
4969 gtk_widget_show(filew);
4972 g_print("%d",gtk_file_selection_match_mask("mask.c","m*.c"));
4973 g_print("%d",gtk_file_selection_match_mask("mask.c","m???.c"));
4974 g_print("%d",gtk_file_selection_match_mask("mask.c","m??*.c"));
4975 g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c"));
4976 g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c???"));
4977 g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c*"));
4978 g_print("%d",gtk_file_selection_match_mask("mask.cout","n*.c???"));
4979 g_print("%d",gtk_file_selection_match_mask("mask.c","[mn]*"));
4980 g_print("%d",gtk_file_selection_match_mask("COPYING","*.xpm"));