4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* type.c - code for dealing with filetypes */
31 #include <sys/param.h>
44 #include "gui_support.h"
60 /* A regexp rule, which maps matching filenames to a MIME-types */
61 typedef struct pattern
{
67 static gboolean o_display_colour_types
= TRUE
;
69 /* Colours for file types (same order as base types) */
70 static gchar
*opt_type_colours
[][2] = {
71 {"display_err_colour", "#ff0000"},
72 {"display_unkn_colour", "#000000"},
73 {"display_dir_colour", "#000080"},
74 {"display_pipe_colour", "#444444"},
75 {"display_sock_colour", "#ff00ff"},
76 {"display_file_colour", "#000000"},
77 {"display_cdev_colour", "#000000"},
78 {"display_bdev_colour", "#000000"},
79 {"display_exec_colour", "#006000"},
80 {"display_adir_colour", "#006000"}
82 #define NUM_TYPE_COLOURS\
83 (sizeof(opt_type_colours) / sizeof(opt_type_colours[0]))
85 /* Parsed colours for file types */
86 static GdkColor type_colours
[NUM_TYPE_COLOURS
];
88 /* Static prototypes */
89 static void alloc_type_colours(void);
90 static char *import_extensions(guchar
*line
);
91 static void import_for_dir(guchar
*path
);
92 char *get_action_save_path(GtkWidget
*dialog
);
93 static void edit_mime_types(guchar
*unused
);
94 static void reread_mime_files(guchar
*unused
);
95 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
);
96 static GList
*build_type_reread(OptionUI
*ui
, xmlNode
*node
, guchar
*label
);
97 static GList
*build_type_edit(OptionUI
*ui
, xmlNode
*node
, guchar
*label
);
99 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *).
100 * Extensions may contain dots; 'tar.gz' matches '*.tar.gz', etc.
101 * The hash table is consulted from each dot in the string in turn
102 * (First .ps.gz, then try .gz)
104 static GHashTable
*extension_hash
= NULL
;
105 static char *current_type
= NULL
; /* (used while reading file) */
107 static GList
*patterns
= NULL
; /* [(regexp -> MIME type)] */
109 /* Hash of all allocated MIME types, indexed by "media/subtype".
110 * MIME_type structs are never freed; this table prevents memory leaks
111 * when rereading the config files.
113 static GHashTable
*type_hash
= NULL
;
115 /* Most things on Unix are text files, so this is the default type */
116 MIME_type
*text_plain
;
117 MIME_type
*special_directory
;
118 MIME_type
*special_pipe
;
119 MIME_type
*special_socket
;
120 MIME_type
*special_block_dev
;
121 MIME_type
*special_char_dev
;
122 MIME_type
*special_exec
;
123 MIME_type
*special_unknown
;
130 extension_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
131 type_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
133 text_plain
= get_mime_type("text/plain", TRUE
);
134 special_directory
= get_mime_type("special/directory", TRUE
);
135 special_pipe
= get_mime_type("special/pipe", TRUE
);
136 special_socket
= get_mime_type("special/socket", TRUE
);
137 special_block_dev
= get_mime_type("special/block-device", TRUE
);
138 special_char_dev
= get_mime_type("special/char-device", TRUE
);
139 special_exec
= get_mime_type("special/executable", TRUE
);
140 special_unknown
= get_mime_type("special/unknown", TRUE
);
144 list
= choices_list_dirs("MIME-info");
145 for (i
= list
->len
- 1; i
>= 0; i
--)
146 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
147 choices_free_list(list
);
149 option_register_widget("type-edit", build_type_edit
);
150 option_register_widget("type-reread", build_type_reread
);
152 option_add_int("display_colour_types", o_display_colour_types
, NULL
);
154 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
155 option_add_string(opt_type_colours
[i
][0],
156 opt_type_colours
[i
][1],
158 alloc_type_colours();
160 option_add_notify(alloc_type_colours
);
163 /* Returns the MIME_type structure for the given type name. It is looked
164 * up in type_hash and returned if found. If not found (and can_create is
165 * TRUE) then a new MIME_type is made, added to type_hash and returned.
166 * NULL is returned if type_name is not in type_hash and can_create is
167 * FALSE, or if type_name does not contain a '/' character.
169 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
)
174 mtype
= g_hash_table_lookup(type_hash
, type_name
);
175 if (mtype
|| !can_create
)
178 slash
= strchr(type_name
, '/');
179 g_return_val_if_fail(slash
!= NULL
, NULL
); /* XXX: Report nicely */
181 mtype
= g_new(MIME_type
, 1);
182 mtype
->media_type
= g_strndup(type_name
, slash
- type_name
);
183 mtype
->subtype
= g_strdup(slash
+ 1);
186 g_hash_table_insert(type_hash
, g_strdup(type_name
), mtype
);
192 static void pattern_delete(gpointer patt
, gpointer udata
)
194 Pattern
*pattern
= (Pattern
*) patt
;
196 regfree(&pattern
->buffer
);
202 static gboolean
extension_delete(gpointer key
, gpointer value
, gpointer udata
)
204 /* key is a g_strdup'ed string */
207 /* value is also preserved in type_hash, so don't delete */
209 return TRUE
; /* Removes this entry */
213 void type_reread(void)
218 g_hash_table_foreach_remove(extension_hash
, extension_delete
, NULL
);
220 g_list_foreach(patterns
, pattern_delete
, NULL
);
221 g_list_free(patterns
);
227 list
= choices_list_dirs("MIME-info");
228 for (i
= list
->len
- 1; i
>= 0; i
--)
229 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
230 choices_free_list(list
);
235 /* Parse every file in 'dir' */
236 static void import_for_dir(guchar
*path
)
245 while ((item
= readdir(dir
)))
250 if (item
->d_name
[0] == '.')
254 file
= make_path(path
, item
->d_name
)->str
;
256 if (stat(file
, &info
) == 0 && S_ISREG(info
.st_mode
))
257 parse_file(file
, import_extensions
);
263 /* Add one entry to the extension_hash table */
264 static void add_ext(char *type_name
, char *ext
)
268 new = get_mime_type(type_name
, TRUE
);
270 g_return_if_fail(new != NULL
);
272 g_hash_table_insert(extension_hash
, g_strdup(ext
), new);
275 static void add_regex(char *type_name
, char *reg
)
282 slash
= strchr(type_name
, '/');
283 g_return_if_fail(slash
!= NULL
); /* XXX: Report nicely */
285 pattern
= g_new0(Pattern
, 1);
287 if (regcomp(&pattern
->buffer
, reg
, REG_EXTENDED
| REG_NOSUB
))
289 regfree(&pattern
->buffer
);
294 new = get_mime_type(type_name
, TRUE
);
296 g_return_if_fail(new != NULL
);
300 patterns
= g_list_prepend(patterns
, pattern
);
304 /* Parse one line from the file and add entries to extension_hash */
305 static char *import_extensions(guchar
*line
)
308 if (*line
== '\0' || *line
== '#')
309 return NULL
; /* Comment */
314 return _("Missing MIME-type");
315 while (*line
&& isspace(*line
))
318 if (strncmp(line
, "ext:", 4) == 0)
325 while (*line
&& isspace(*line
))
330 while (*line
&& !isspace(*line
))
334 add_ext(current_type
, ext
);
337 else if (strncmp(line
, "regex:", 6) == 0)
341 while (*line
&& isspace(*line
))
344 add_regex(current_type
, line
);
351 while (*line
&& *line
!= ':' && !isspace(*line
))
355 while (*line
&& isspace(*line
))
358 return _("Trailing chars after MIME-type");
359 current_type
= g_strdup(type
);
364 char *basetype_name(DirItem
*item
)
366 if (item
->flags
& ITEM_FLAG_SYMLINK
)
367 return _("Sym link");
368 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
369 return _("Mount point");
370 else if (item
->flags
& ITEM_FLAG_APPDIR
)
373 switch (item
->base_type
)
379 case TYPE_CHAR_DEVICE
:
380 return _("Char dev");
381 case TYPE_BLOCK_DEVICE
:
382 return _("Block dev");
392 /* MIME-type guessing */
394 /* Get the type of this file - stats the file and uses that if
395 * possible. For regular or missing files, uses the pathname.
397 MIME_type
*type_get_type(guchar
*path
)
400 MIME_type
*type
= NULL
;
401 int base
= TYPE_FILE
;
402 gboolean exec
= FALSE
;
404 if (mc_stat(path
, &info
) == 0)
406 base
= mode_to_base_type(info
.st_mode
);
407 if (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))
411 if (base
== TYPE_FILE
)
412 type
= type_from_path(path
);
416 if (base
== TYPE_FILE
&& exec
)
419 type
= mime_type_from_base_type(base
);
425 /* Returns a pointer to the MIME-type.
426 * NULL if we can't think of anything.
428 MIME_type
*type_from_path(char *path
)
430 char *ext
, *dot
, *lower
, *leafname
;
436 leafname
= strrchr(path
, '/');
443 while ((dot
= strchr(ext
, '.')))
449 type
= g_hash_table_lookup(extension_hash
, ext
);
454 lower
= g_strdup(ext
);
456 type
= g_hash_table_lookup(extension_hash
, lower
);
464 len
= strlen(leafname
);
466 for (patt
= patterns
; patt
; patt
= patt
->next
)
468 Pattern
*pattern
= (Pattern
*) patt
->data
;
470 if (regexec(&pattern
->buffer
, leafname
, 0, NULL
, 0) == 0)
471 return pattern
->type
;
478 /* Returns the file/dir in Choices for handling this type.
479 * NULL if there isn't one. g_free() the result.
481 static char *handler_for(MIME_type
*type
)
486 type_name
= g_strconcat(type
->media_type
, "_", type
->subtype
, NULL
);
487 open
= choices_find_path_load(type_name
, "MIME-types");
491 open
= choices_find_path_load(type
->media_type
, "MIME-types");
496 /* Actions for types */
498 gboolean
type_open(char *path
, MIME_type
*type
)
500 char *argv
[] = {NULL
, NULL
, NULL
};
507 open
= handler_for(type
);
511 if (stat(open
, &info
))
513 report_error("stat(%s): %s", open
, g_strerror(errno
));
518 if (S_ISDIR(info
.st_mode
))
519 argv
[0] = g_strconcat(open
, "/AppRun", NULL
);
523 retval
= rox_spawn(home_dir
, argv
);
533 /* Return the image for this type, loading it if needed.
534 * Places to check are: (eg type="text_plain", base="text")
535 * 1. Choices:MIME-icons/<type>
536 * 2. Choices:MIME-icons/<base>
537 * 3. Unknown type icon.
539 * Note: You must pixmap_unref() the image afterwards.
541 MaskedPixmap
*type_to_icon(MIME_type
*type
)
549 pixmap_ref(im_unknown
);
554 /* Already got an image? */
557 /* Yes - don't recheck too often */
558 if (abs(now
- type
->image_time
) < 2)
560 pixmap_ref(type
->image
);
563 pixmap_unref(type
->image
);
567 type_name
= g_strconcat(type
->media_type
, "_",
568 type
->subtype
, ".xpm", NULL
);
569 path
= choices_find_path_load(type_name
, "MIME-icons");
572 strcpy(type_name
+ strlen(type
->media_type
), ".xpm");
573 path
= choices_find_path_load(type_name
, "MIME-icons");
580 type
->image
= g_fscache_lookup(pixmap_cache
, path
);
586 /* One ref from the type structure, one returned */
587 type
->image
= im_unknown
;
588 pixmap_ref(im_unknown
);
591 type
->image_time
= now
;
593 pixmap_ref(type
->image
);
597 GdkAtom
type_to_atom(MIME_type
*type
)
602 g_return_val_if_fail(type
!= NULL
, GDK_NONE
);
604 str
= g_strconcat(type
->media_type
, "/", type
->subtype
, NULL
);
605 retval
= gdk_atom_intern(str
, FALSE
);
611 void show_shell_help(gpointer data
)
613 report_error(_("Enter a shell command which will load \"$1\" into "
614 "a suitable program. Eg:\n\n"
618 /* Called if the user clicks on the OK button */
619 static void set_shell_action(GtkWidget
*dialog
)
622 GtkToggleButton
*for_all
;
623 guchar
*command
, *path
, *tmp
;
627 entry
= gtk_object_get_data(GTK_OBJECT(dialog
), "shell_command");
628 for_all
= gtk_object_get_data(GTK_OBJECT(dialog
), "set_for_all");
629 g_return_if_fail(entry
!= NULL
);
631 command
= gtk_entry_get_text(entry
);
633 if (!strchr(command
, '$'))
635 show_shell_help(NULL
);
639 path
= get_action_save_path(dialog
);
643 tmp
= g_strdup_printf("#! /bin/sh\nexec %s\n", command
);
646 file
= fopen(path
, "wb");
647 if (fwrite(tmp
, 1, len
, file
) < len
)
649 if (fclose(file
) && error
== 0)
651 if (chmod(path
, 0777))
655 report_error(g_strerror(errno
));
660 gtk_widget_destroy(dialog
);
663 /* Called when a URI list is dropped onto the box in the Set Run Action
664 * dialog. Make sure it's an application, and make that the default
667 void drag_app_dropped(GtkWidget
*eb
,
668 GdkDragContext
*context
,
671 GtkSelectionData
*selection_data
,
680 if (!selection_data
->data
)
681 return; /* Timeout? */
683 uris
= uri_list_to_glist(selection_data
->data
);
685 if (g_list_length(uris
) == 1)
686 app
= get_local_path((guchar
*) uris
->data
);
692 _("You should drop a single (local) application "
693 "onto the drop box - that application will be "
694 "used to load files of this type in future"));
698 item
= diritem_new(NULL
);
699 diritem_restat(app
, item
);
700 if (item
->flags
& (ITEM_FLAG_APPDIR
| ITEM_FLAG_EXEC_FILE
))
704 path
= get_action_save_path(dialog
);
708 if (symlink(app
, path
))
709 delayed_error("symlink: %s",
712 destroy_on_idle(dialog
);
719 _("This is not a program! Give me an application "
725 /* Find the current command which is used to run files of this type.
726 * Returns NULL on failure. g_free() the result.
728 static guchar
*get_current_command(MIME_type
*type
)
731 char *handler
, *nl
, *data
= NULL
;
733 guchar
*command
= NULL
;
735 handler
= handler_for(type
);
738 return NULL
; /* No current handler */
740 if (stat(handler
, &info
))
741 goto out
; /* Can't stat */
743 if ((!S_ISREG(info
.st_mode
)) || info
.st_size
> 256)
744 goto out
; /* Only use small regular files */
746 if (!load_file(handler
, &data
, &len
))
747 goto out
; /* Didn't load OK */
749 if (strncmp(data
, "#! /bin/sh\nexec ", 16) != 0)
750 goto out
; /* Not one of ours */
752 nl
= strchr(data
+ 16, '\n');
754 goto out
; /* No newline! */
756 command
= g_strndup(data
+ 16, nl
- data
- 16);
763 /* Find the current command which is used to run files of this type,
764 * and return a textual description of it.
765 * g_free() the result.
767 gchar
*describe_current_command(MIME_type
*type
)
774 g_return_val_if_fail(type
!= NULL
, NULL
);
776 if (type
== special_exec
)
777 return g_strdup(_("Execute file"));
779 handler
= handler_for(type
);
782 return g_strdup(_("No run action defined"));
784 target
= readlink_dup(handler
);
787 /* Cope with relative paths (shouldn't normally be needed) */
789 if (target
[0] == '/')
798 dir
= g_dirname(handler
);
800 handler
= g_strconcat(dir
, "/", target
, NULL
);
806 if (mc_stat(handler
, &info
) !=0 )
808 desc
= g_strdup_printf(_("Error in handler %s: %s"), handler
,
813 if (S_ISDIR(info
.st_mode
))
816 uid_t dir_uid
= info
.st_uid
;
818 tmp
= make_path(handler
, "AppRun")->str
;
820 if (mc_lstat(tmp
, &info
) != 0 || info
.st_uid
!= dir_uid
821 || !(info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
822 desc
= g_strdup_printf(
823 _("Invalid application %s (bad AppRun)"),
825 /* Else, just report handler... */
830 /* It's not an application directory, and it's not a symlink... */
832 if (access(handler
, X_OK
) != 0)
834 desc
= g_strdup_printf(_("Non-executable %s"), handler
);
838 desc
= get_current_command(type
);
848 /* Display a dialog box allowing the user to set the default run action
851 void type_set_handler_dialog(MIME_type
*type
)
855 GtkWidget
*dialog
, *vbox
, *frame
, *hbox
, *entry
, *label
, *button
;
856 GtkWidget
*radio
, *eb
;
857 GtkTargetEntry targets
[] = {
858 {"text/uri-list", 0, TARGET_URI_LIST
},
861 g_return_if_fail(type
!= NULL
);
863 dialog
= gtk_window_new(GTK_WINDOW_DIALOG
);
865 gtk_window_set_type_hint(GTK_WINDOW(dialog
),
866 GDK_WINDOW_TYPE_HINT_DIALOG
);
868 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
869 gtk_object_set_data(GTK_OBJECT(dialog
), "mime_type", type
);
871 gtk_window_set_title(GTK_WINDOW(dialog
), _("Set run action"));
872 gtk_container_set_border_width(GTK_CONTAINER(dialog
), 10);
874 vbox
= gtk_vbox_new(FALSE
, 4);
875 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
877 tmp
= g_strdup_printf(_("Set default for all `%s/<anything>'"),
879 radio
= gtk_radio_button_new_with_label(NULL
, tmp
);
881 gtk_object_set_data(GTK_OBJECT(dialog
), "set_for_all", radio
);
883 tmp
= g_strdup_printf(_("Only for the type `%s/%s'"), type
->media_type
,
885 gtk_box_pack_start(GTK_BOX(vbox
), radio
, FALSE
, TRUE
, 0);
886 radio
= gtk_radio_button_new_with_label(
887 gtk_radio_button_group(GTK_RADIO_BUTTON(radio
)),
890 gtk_box_pack_start(GTK_BOX(vbox
), radio
, FALSE
, TRUE
, 0);
891 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio
), TRUE
);
893 frame
= gtk_frame_new(NULL
);
894 gtk_box_pack_start(GTK_BOX(vbox
), frame
, TRUE
, TRUE
, 4);
895 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_IN
);
896 eb
= gtk_event_box_new();
897 gtk_container_add(GTK_CONTAINER(frame
), eb
);
899 gtk_container_set_border_width(GTK_CONTAINER(eb
), 4);
901 handler
= handler_for(type
);
906 link
= readlink_dup(handler
);
911 msg
= g_strdup_printf(_("Currently %s"), link
);
912 gtk_tooltips_set_tip(tooltips
, eb
, msg
, NULL
);
919 gtk_drag_dest_set(eb
, GTK_DEST_DEFAULT_ALL
,
920 targets
, sizeof(targets
) / sizeof(*targets
),
922 gtk_signal_connect(GTK_OBJECT(eb
), "drag_data_received",
923 GTK_SIGNAL_FUNC(drag_app_dropped
), dialog
);
925 label
= gtk_label_new(_("Drop a suitable\napplication here"));
926 gtk_misc_set_padding(GTK_MISC(label
), 10, 20);
927 gtk_container_add(GTK_CONTAINER(eb
), label
);
929 hbox
= gtk_hbox_new(FALSE
, 4);
930 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 4);
931 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
932 gtk_box_pack_start(GTK_BOX(hbox
), gtk_label_new(_("OR")),
934 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
936 hbox
= gtk_hbox_new(FALSE
, 4);
937 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
939 label
= gtk_label_new(_("Enter a shell command:")),
940 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
941 gtk_box_pack_start(GTK_BOX(hbox
), label
, TRUE
, TRUE
, 4);
943 gtk_box_pack_start(GTK_BOX(hbox
),
944 new_help_button(show_shell_help
, NULL
), FALSE
, TRUE
, 0);
946 entry
= gtk_entry_new();
947 gtk_box_pack_start(GTK_BOX(vbox
), entry
, FALSE
, TRUE
, 0);
948 gtk_widget_grab_focus(entry
);
949 gtk_object_set_data(GTK_OBJECT(dialog
), "shell_command", entry
);
950 gtk_signal_connect_object(GTK_OBJECT(entry
), "activate",
951 GTK_SIGNAL_FUNC(set_shell_action
), GTK_OBJECT(dialog
));
953 hbox
= gtk_hbox_new(TRUE
, 4);
954 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
956 /* If possible, fill in the entry box with the current command */
957 tmp
= get_current_command(type
);
960 gtk_entry_set_text(GTK_ENTRY(entry
), tmp
);
961 gtk_entry_set_position(GTK_ENTRY(entry
), -1);
966 gtk_entry_set_text(GTK_ENTRY(entry
), " \"$1\"");
967 gtk_entry_set_position(GTK_ENTRY(entry
), 0);
970 button
= gtk_button_new_with_label(_("OK"));
971 gtk_box_pack_start(GTK_BOX(hbox
), button
, TRUE
, TRUE
, 0);
972 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
973 gtk_window_set_default(GTK_WINDOW(dialog
), button
);
974 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
975 GTK_SIGNAL_FUNC(set_shell_action
), GTK_OBJECT(dialog
));
977 button
= gtk_button_new_with_label(_("Cancel"));
978 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
979 gtk_box_pack_start(GTK_BOX(hbox
), button
, TRUE
, TRUE
, 0);
980 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
981 GTK_SIGNAL_FUNC(gtk_widget_destroy
),
984 gtk_widget_show_all(dialog
);
987 /* The user wants to set a new default action for files of this type.
988 * Removes the current binding if possible and returns the path to
989 * save the new one to. NULL means cancel. g_free() the result.
991 char *get_action_save_path(GtkWidget
*dialog
)
995 guchar
*type_name
= NULL
;
997 GtkToggleButton
*for_all
;
999 g_return_val_if_fail(dialog
!= NULL
, NULL
);
1000 type
= gtk_object_get_data(GTK_OBJECT(dialog
), "mime_type");
1001 for_all
= gtk_object_get_data(GTK_OBJECT(dialog
), "set_for_all");
1002 g_return_val_if_fail(for_all
!= NULL
&& type
!= NULL
, NULL
);
1004 if (gtk_toggle_button_get_active(for_all
))
1005 type_name
= g_strdup(type
->media_type
);
1007 type_name
= g_strconcat(type
->media_type
, "_",
1008 type
->subtype
, NULL
);
1010 path
= choices_find_path_save("", PROJECT
, FALSE
);
1014 _("Choices saving is disabled by CHOICESPATH variable"));
1019 path
= choices_find_path_save(type_name
, "MIME-types", TRUE
);
1021 if (lstat(path
, &info
) == 0)
1023 /* A binding already exists... */
1024 if (S_ISREG(info
.st_mode
) && info
.st_size
> 256)
1026 if (get_choice(PROJECT
,
1027 _("A run action already exists and is quite "
1028 "a big program - are you sure you want to "
1029 "delete it?"), 2, "Cancel", "Delete") != 1)
1039 report_error(_("Can't remove %s: %s"),
1040 path
, g_strerror(errno
));
1052 MIME_type
*mime_type_from_base_type(int base_type
)
1058 case TYPE_DIRECTORY
:
1059 return special_directory
;
1061 return special_pipe
;
1063 return special_socket
;
1064 case TYPE_BLOCK_DEVICE
:
1065 return special_block_dev
;
1066 case TYPE_CHAR_DEVICE
:
1067 return special_char_dev
;
1069 return special_unknown
;
1072 /* Takes the st_mode field from stat() and returns the base type.
1073 * Should not be a symlink.
1075 int mode_to_base_type(int st_mode
)
1077 if (S_ISREG(st_mode
))
1079 else if (S_ISDIR(st_mode
))
1080 return TYPE_DIRECTORY
;
1081 else if (S_ISBLK(st_mode
))
1082 return TYPE_BLOCK_DEVICE
;
1083 else if (S_ISCHR(st_mode
))
1084 return TYPE_CHAR_DEVICE
;
1085 else if (S_ISFIFO(st_mode
))
1087 else if (S_ISSOCK(st_mode
))
1093 /* Returns TRUE is this is something that is run by looking up its type
1094 * in MIME-types and, hence, can have its run action set.
1096 gboolean
can_set_run_action(DirItem
*item
)
1098 g_return_val_if_fail(item
!= NULL
, FALSE
);
1100 return item
->base_type
== TYPE_FILE
&&
1101 !(item
->mime_type
== special_exec
);
1104 /* Open all <Choices>/type directories and display a message */
1105 static void open_choices_dirs(gchar
*type
, gchar
*what
)
1111 dir
= choices_find_path_save("", type
, TRUE
);
1113 list
= choices_list_dirs(type
);
1115 for (i
= list
->len
- 1; i
>= 0; i
--)
1116 filer_opendir(list
->pdata
[i
], NULL
);
1118 choices_free_list(list
);
1121 /* To edit the MIME types, open a filer window for <Choices>/MIME-info */
1122 static void edit_mime_types(guchar
*unused
)
1124 open_choices_dirs("MIME-info", "the files defining MIME types");
1127 static void reread_mime_files(guchar
*unused
)
1132 static GList
*build_type_reread(OptionUI
*none
, xmlNode
*node
, guchar
*label
)
1134 GtkWidget
*button
, *align
;
1136 align
= gtk_alignment_new(0.1, 0, 0.1, 0);
1137 button
= gtk_button_new_with_label(_(label
));
1138 gtk_container_add(GTK_CONTAINER(align
), button
);
1140 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
1141 GTK_SIGNAL_FUNC(reread_mime_files
), NULL
);
1143 return g_list_append(NULL
, align
);
1146 static GList
*build_type_edit(OptionUI
*none
, xmlNode
*node
, guchar
*label
)
1148 GtkWidget
*button
, *align
;
1150 align
= gtk_alignment_new(0.1, 0, 0.1, 0);
1151 button
= gtk_button_new_with_label(_(label
));
1152 gtk_container_add(GTK_CONTAINER(align
), button
);
1154 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
1155 GTK_SIGNAL_FUNC(edit_mime_types
), NULL
);
1157 return g_list_append(NULL
, align
);
1160 /* Parse file type colours and allocate/free them as necessary */
1161 static void alloc_type_colours(void)
1163 gboolean success
[NUM_TYPE_COLOURS
];
1164 int change_count
= 0; /* No. needing realloc */
1166 static gboolean allocated
= FALSE
;
1168 o_display_colour_types
= option_get_int("display_colour_types");
1171 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
1173 GdkColor
*c
= &type_colours
[i
];
1175 gushort g
= c
->green
;
1176 gushort b
= c
->blue
;
1179 option_get_static_string(opt_type_colours
[i
][0]),
1182 if (allocated
&& (c
->red
!= r
|| c
->green
!= g
|| c
->blue
!= b
))
1186 /* Free colours if they were previously allocated and
1187 * have changed or become unneeded.
1189 if (allocated
&& (change_count
|| !o_display_colour_types
))
1191 gdk_colormap_free_colors(gdk_rgb_get_cmap(),
1192 type_colours
, NUM_TYPE_COLOURS
);
1196 /* Allocate colours, unless they are still allocated (=> they didn't
1197 * change) or we don't want them anymore.
1198 * XXX: what should be done if allocation fails?
1200 if (!allocated
&& o_display_colour_types
)
1202 gdk_colormap_alloc_colors(gdk_rgb_get_cmap(),
1203 type_colours
, NUM_TYPE_COLOURS
,
1204 FALSE
, TRUE
, success
);
1209 /* Return a pointer to a (static) colour for this item. If colouring is
1210 * off, returns normal.
1212 GdkColor
*type_get_colour(DirItem
*item
, GdkColor
*normal
)
1214 if (!o_display_colour_types
)
1217 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
1218 return &type_colours
[8];
1219 else if (item
->flags
& ITEM_FLAG_APPDIR
)
1220 return &type_colours
[9];
1222 return &type_colours
[item
->base_type
];