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>
38 # include <libgnomevfs/gnome-vfs.h>
39 # include <libgnomevfs/gnome-vfs-mime.h>
40 # include <libgnomevfs/gnome-vfs-mime-handlers.h>
41 # include <libgnomevfs/gnome-vfs-application-registry.h>
51 #include "gui_support.h"
67 /* A regexp rule, which maps matching filenames to a MIME-types */
68 typedef struct pattern
{
74 static Option o_use_gnomevfs
;
76 /* Colours for file types (same order as base types) */
77 static gchar
*opt_type_colours
[][2] = {
78 {"display_err_colour", "#ff0000"},
79 {"display_unkn_colour", "#000000"},
80 {"display_dir_colour", "#000080"},
81 {"display_pipe_colour", "#444444"},
82 {"display_sock_colour", "#ff00ff"},
83 {"display_file_colour", "#000000"},
84 {"display_cdev_colour", "#000000"},
85 {"display_bdev_colour", "#000000"},
86 {"display_exec_colour", "#006000"},
87 {"display_adir_colour", "#006000"}
89 #define NUM_TYPE_COLOURS\
90 (sizeof(opt_type_colours) / sizeof(opt_type_colours[0]))
92 /* Parsed colours for file types */
93 static Option o_type_colours
[NUM_TYPE_COLOURS
];
94 static GdkColor type_colours
[NUM_TYPE_COLOURS
];
96 /* Static prototypes */
97 static void alloc_type_colours(void);
98 static const char *import_extensions(gchar
*line
);
99 static void import_for_dir(guchar
*path
);
100 char *get_action_save_path(GtkWidget
*dialog
);
101 static void edit_mime_types(guchar
*unused
);
102 static void reread_mime_files(guchar
*unused
);
103 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
);
104 static GList
*build_type_reread(Option
*none
, xmlNode
*node
, guchar
*label
);
105 static GList
*build_type_edit(Option
*none
, xmlNode
*node
, guchar
*label
);
107 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *).
108 * Extensions may contain dots; 'tar.gz' matches '*.tar.gz', etc.
109 * The hash table is consulted from each dot in the string in turn
110 * (First .ps.gz, then try .gz)
112 static GHashTable
*extension_hash
= NULL
;
113 static char *current_type
= NULL
; /* (used while reading file) */
115 static GList
*patterns
= NULL
; /* [(regexp -> MIME type)] */
117 /* Hash of all allocated MIME types, indexed by "media/subtype".
118 * MIME_type structs are never freed; this table prevents memory leaks
119 * when rereading the config files.
121 static GHashTable
*type_hash
= NULL
;
123 /* Most things on Unix are text files, so this is the default type */
124 MIME_type
*text_plain
;
125 MIME_type
*special_directory
;
126 MIME_type
*special_pipe
;
127 MIME_type
*special_socket
;
128 MIME_type
*special_block_dev
;
129 MIME_type
*special_char_dev
;
130 MIME_type
*special_exec
;
131 MIME_type
*special_unknown
;
133 static Option o_display_colour_types
;
140 extension_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
141 type_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
143 text_plain
= get_mime_type("text/plain", TRUE
);
144 special_directory
= get_mime_type("special/directory", TRUE
);
145 special_pipe
= get_mime_type("special/pipe", TRUE
);
146 special_socket
= get_mime_type("special/socket", TRUE
);
147 special_block_dev
= get_mime_type("special/block-device", TRUE
);
148 special_char_dev
= get_mime_type("special/char-device", TRUE
);
149 special_exec
= get_mime_type("special/executable", TRUE
);
150 special_unknown
= get_mime_type("special/unknown", TRUE
);
154 list
= choices_list_dirs("MIME-info");
155 for (i
= list
->len
- 1; i
>= 0; i
--)
156 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
157 choices_free_list(list
);
159 option_register_widget("type-edit", build_type_edit
);
160 option_register_widget("type-reread", build_type_reread
);
162 option_add_int(&o_display_colour_types
, "display_colour_types", TRUE
);
163 option_add_int(&o_use_gnomevfs
, "use_gnomevfs", TRUE
);
165 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
166 option_add_string(&o_type_colours
[i
],
167 opt_type_colours
[i
][0],
168 opt_type_colours
[i
][1]);
169 alloc_type_colours();
171 option_add_notify(alloc_type_colours
);
174 /* Returns the MIME_type structure for the given type name. It is looked
175 * up in type_hash and returned if found. If not found (and can_create is
176 * TRUE) then a new MIME_type is made, added to type_hash and returned.
177 * NULL is returned if type_name is not in type_hash and can_create is
178 * FALSE, or if type_name does not contain a '/' character.
180 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
)
185 mtype
= g_hash_table_lookup(type_hash
, type_name
);
186 if (mtype
|| !can_create
)
189 slash
= strchr(type_name
, '/');
190 g_return_val_if_fail(slash
!= NULL
, NULL
); /* XXX: Report nicely */
192 mtype
= g_new(MIME_type
, 1);
193 mtype
->media_type
= g_strndup(type_name
, slash
- type_name
);
194 mtype
->subtype
= g_strdup(slash
+ 1);
197 g_hash_table_insert(type_hash
, g_strdup(type_name
), mtype
);
203 static void pattern_delete(gpointer patt
, gpointer udata
)
205 Pattern
*pattern
= (Pattern
*) patt
;
207 regfree(&pattern
->buffer
);
213 static gboolean
extension_delete(gpointer key
, gpointer value
, gpointer udata
)
215 /* key is a g_strdup'ed string */
218 /* value is also preserved in type_hash, so don't delete */
220 return TRUE
; /* Removes this entry */
224 void type_reread(void)
229 g_hash_table_foreach_remove(extension_hash
, extension_delete
, NULL
);
231 g_list_foreach(patterns
, pattern_delete
, NULL
);
232 g_list_free(patterns
);
238 list
= choices_list_dirs("MIME-info");
239 for (i
= list
->len
- 1; i
>= 0; i
--)
240 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
241 choices_free_list(list
);
246 /* Parse every file in 'dir' */
247 static void import_for_dir(guchar
*path
)
256 while ((item
= readdir(dir
)))
261 if (item
->d_name
[0] == '.')
265 file
= make_path(path
, item
->d_name
)->str
;
267 if (stat(file
, &info
) == 0 && S_ISREG(info
.st_mode
))
268 parse_file(file
, import_extensions
);
274 /* Add one entry to the extension_hash table */
275 static void add_ext(const char *type_name
, const char *ext
)
279 new = get_mime_type(type_name
, TRUE
);
281 g_return_if_fail(new != NULL
);
283 g_hash_table_insert(extension_hash
, g_strdup(ext
), new);
286 static void add_regex(char *type_name
, char *reg
)
293 slash
= strchr(type_name
, '/');
294 g_return_if_fail(slash
!= NULL
); /* XXX: Report nicely */
296 pattern
= g_new0(Pattern
, 1);
298 if (regcomp(&pattern
->buffer
, reg
, REG_EXTENDED
| REG_NOSUB
))
300 regfree(&pattern
->buffer
);
305 new = get_mime_type(type_name
, TRUE
);
307 g_return_if_fail(new != NULL
);
311 patterns
= g_list_prepend(patterns
, pattern
);
315 /* Parse one line from the file and add entries to extension_hash */
316 static const char *import_extensions(gchar
*line
)
318 if (*line
== '\0' || *line
== '#')
319 return NULL
; /* Comment */
324 return _("Missing MIME-type");
325 while (*line
&& isspace(*line
))
328 if (strncmp(line
, "ext:", 4) == 0)
335 while (*line
&& isspace(*line
))
340 while (*line
&& !isspace(*line
))
344 add_ext(current_type
, ext
);
347 else if (strncmp(line
, "regex:", 6) == 0)
351 while (*line
&& isspace(*line
))
354 add_regex(current_type
, line
);
361 while (*line
&& *line
!= ':' && !isspace(*line
))
365 while (*line
&& isspace(*line
))
368 return _("Trailing chars after MIME-type");
369 current_type
= g_strdup(type
);
374 const char *basetype_name(DirItem
*item
)
376 if (item
->flags
& ITEM_FLAG_SYMLINK
)
377 return _("Sym link");
378 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
379 return _("Mount point");
380 else if (item
->flags
& ITEM_FLAG_APPDIR
)
383 switch (item
->base_type
)
389 case TYPE_CHAR_DEVICE
:
390 return _("Char dev");
391 case TYPE_BLOCK_DEVICE
:
392 return _("Block dev");
402 /* MIME-type guessing */
404 /* Get the type of this file - stats the file and uses that if
405 * possible. For regular or missing files, uses the pathname.
407 MIME_type
*type_get_type(const guchar
*path
)
410 MIME_type
*type
= NULL
;
411 int base
= TYPE_FILE
;
412 gboolean exec
= FALSE
;
414 if (mc_stat(path
, &info
) == 0)
416 base
= mode_to_base_type(info
.st_mode
);
417 if (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))
421 if (base
== TYPE_FILE
)
422 type
= type_from_path(path
);
426 if (base
== TYPE_FILE
&& exec
)
429 type
= mime_type_from_base_type(base
);
435 /* Returns a pointer to the MIME-type.
436 * NULL if we can't think of anything.
438 MIME_type
*type_from_path(const char *path
)
440 const char *ext
, *dot
, *leafname
;
448 if (o_use_gnomevfs
.int_value
)
449 return get_mime_type(gnome_vfs_mime_type_from_name(path
), TRUE
);
452 leafname
= strrchr(path
, '/');
459 while ((dot
= strchr(ext
, '.')))
465 type
= g_hash_table_lookup(extension_hash
, ext
);
470 lower
= g_strdup(ext
);
472 type
= g_hash_table_lookup(extension_hash
, lower
);
480 len
= strlen(leafname
);
482 for (patt
= patterns
; patt
; patt
= patt
->next
)
484 Pattern
*pattern
= (Pattern
*) patt
->data
;
486 if (regexec(&pattern
->buffer
, leafname
, 0, NULL
, 0) == 0)
487 return pattern
->type
;
494 /* Returns the file/dir in Choices for handling this type.
495 * NULL if there isn't one. g_free() the result.
497 static char *handler_for(MIME_type
*type
)
502 type_name
= g_strconcat(type
->media_type
, "_", type
->subtype
, NULL
);
503 open
= choices_find_path_load(type_name
, "MIME-types");
507 open
= choices_find_path_load(type
->media_type
, "MIME-types");
512 /* Actions for types */
514 gboolean
type_open(const char *path
, MIME_type
*type
)
516 gchar
*argv
[] = {NULL
, NULL
, NULL
};
521 argv
[1] = (char *) path
;
523 open
= handler_for(type
);
527 if (stat(open
, &info
))
529 report_error("stat(%s): %s", open
, g_strerror(errno
));
534 if (S_ISDIR(info
.st_mode
))
535 argv
[0] = g_strconcat(open
, "/AppRun", NULL
);
539 retval
= rox_spawn(home_dir
, (const gchar
**) argv
);
549 /* Return the image for this type, loading it if needed.
550 * Places to check are: (eg type="text_plain", base="text")
551 * 1. Choices:MIME-icons/<type>
552 * 2. Choices:MIME-icons/<base>
553 * 3. Unknown type icon.
555 * Note: You must g_object_unref() the image afterwards.
557 MaskedPixmap
*type_to_icon(MIME_type
*type
)
565 g_object_ref(im_unknown
);
570 /* Already got an image? */
573 /* Yes - don't recheck too often */
574 if (abs(now
- type
->image_time
) < 2)
576 g_object_ref(type
->image
);
579 g_object_unref(type
->image
);
583 type_name
= g_strconcat(type
->media_type
, "_",
584 type
->subtype
, ".xpm", NULL
);
585 path
= choices_find_path_load(type_name
, "MIME-icons");
588 strcpy(type_name
+ strlen(type
->media_type
), ".xpm");
589 path
= choices_find_path_load(type_name
, "MIME-icons");
596 type
->image
= g_fscache_lookup(pixmap_cache
, path
);
602 /* One ref from the type structure, one returned */
603 type
->image
= im_unknown
;
604 g_object_ref(im_unknown
);
607 type
->image_time
= now
;
609 g_object_ref(type
->image
);
613 GdkAtom
type_to_atom(MIME_type
*type
)
618 g_return_val_if_fail(type
!= NULL
, GDK_NONE
);
620 str
= g_strconcat(type
->media_type
, "/", type
->subtype
, NULL
);
621 retval
= gdk_atom_intern(str
, FALSE
);
627 void show_shell_help(gpointer data
)
629 report_error(_("Enter a shell command which will load \"$1\" into "
630 "a suitable program. Eg:\n\n"
634 /* Called if the user clicks on the OK button */
635 static void set_shell_action(GtkWidget
*dialog
)
638 GtkToggleButton
*for_all
;
639 const guchar
*command
;
644 entry
= g_object_get_data(G_OBJECT(dialog
), "shell_command");
645 for_all
= g_object_get_data(G_OBJECT(dialog
), "set_for_all");
646 g_return_if_fail(entry
!= NULL
);
648 command
= gtk_entry_get_text(entry
);
650 if (!strchr(command
, '$'))
652 show_shell_help(NULL
);
656 path
= get_action_save_path(dialog
);
660 tmp
= g_strdup_printf("#! /bin/sh\nexec %s\n", command
);
663 file
= fopen(path
, "wb");
664 if (fwrite(tmp
, 1, len
, file
) < len
)
666 if (fclose(file
) && error
== 0)
668 if (chmod(path
, 0777))
672 report_error(g_strerror(errno
));
677 gtk_widget_destroy(dialog
);
680 static void set_action_response(GtkWidget
*dialog
, gint response
, gpointer data
)
682 if (response
== GTK_RESPONSE_OK
)
683 set_shell_action(dialog
);
684 gtk_widget_destroy(dialog
);
687 /* Called when a URI list is dropped onto the box in the Set Run Action
688 * dialog. Make sure it's an application, and make that the default
691 void drag_app_dropped(GtkWidget
*eb
,
692 GdkDragContext
*context
,
695 GtkSelectionData
*selection_data
,
701 const gchar
*app
= NULL
;
704 if (!selection_data
->data
)
705 return; /* Timeout? */
707 uris
= uri_list_to_glist(selection_data
->data
);
709 if (g_list_length(uris
) == 1)
710 app
= get_local_path((guchar
*) uris
->data
);
716 _("You should drop a single (local) application "
717 "onto the drop box - that application will be "
718 "used to load files of this type in future"));
722 item
= diritem_new(NULL
);
723 diritem_restat(app
, item
);
724 if (item
->flags
& (ITEM_FLAG_APPDIR
| ITEM_FLAG_EXEC_FILE
))
728 path
= get_action_save_path(dialog
);
732 if (symlink(app
, path
))
733 delayed_error("symlink: %s",
736 destroy_on_idle(dialog
);
743 _("This is not a program! Give me an application "
749 /* Find the current command which is used to run files of this type.
750 * Returns NULL on failure. g_free() the result.
752 static guchar
*get_current_command(MIME_type
*type
)
755 char *handler
, *nl
, *data
= NULL
;
757 guchar
*command
= NULL
;
759 handler
= handler_for(type
);
762 return NULL
; /* No current handler */
764 if (stat(handler
, &info
))
765 goto out
; /* Can't stat */
767 if ((!S_ISREG(info
.st_mode
)) || info
.st_size
> 256)
768 goto out
; /* Only use small regular files */
770 if (!load_file(handler
, &data
, &len
))
771 goto out
; /* Didn't load OK */
773 if (strncmp(data
, "#! /bin/sh\nexec ", 16) != 0)
774 goto out
; /* Not one of ours */
776 nl
= strchr(data
+ 16, '\n');
778 goto out
; /* No newline! */
780 command
= g_strndup(data
+ 16, nl
- data
- 16);
787 /* Find the current command which is used to run files of this type,
788 * and return a textual description of it.
789 * g_free() the result.
791 gchar
*describe_current_command(MIME_type
*type
)
798 g_return_val_if_fail(type
!= NULL
, NULL
);
800 if (type
== special_exec
)
801 return g_strdup(_("Execute file"));
803 handler
= handler_for(type
);
806 return g_strdup(_("No run action defined"));
808 target
= readlink_dup(handler
);
811 /* Cope with relative paths (shouldn't normally be needed) */
813 if (target
[0] == '/')
822 dir
= g_dirname(handler
);
824 handler
= g_strconcat(dir
, "/", target
, NULL
);
830 if (mc_stat(handler
, &info
) !=0 )
832 desc
= g_strdup_printf(_("Error in handler %s: %s"), handler
,
837 if (S_ISDIR(info
.st_mode
))
840 uid_t dir_uid
= info
.st_uid
;
842 tmp
= make_path(handler
, "AppRun")->str
;
844 if (mc_lstat(tmp
, &info
) != 0 || info
.st_uid
!= dir_uid
845 || !(info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
846 desc
= g_strdup_printf(
847 _("Invalid application %s (bad AppRun)"),
849 /* Else, just report handler... */
854 /* It's not an application directory, and it's not a symlink... */
856 if (access(handler
, X_OK
) != 0)
858 desc
= g_strdup_printf(_("Non-executable %s"), handler
);
862 desc
= get_current_command(type
);
872 /* Display a dialog box allowing the user to set the default run action
875 void type_set_handler_dialog(MIME_type
*type
)
880 GtkWidget
*frame
, *entry
, *label
;
881 GtkWidget
*radio
, *eb
, *hbox
;
882 GtkTargetEntry targets
[] = {
883 {"text/uri-list", 0, TARGET_URI_LIST
},
886 g_return_if_fail(type
!= NULL
);
888 dialog
= GTK_DIALOG(gtk_dialog_new());
889 gtk_dialog_set_has_separator(dialog
, FALSE
);
890 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
892 g_object_set_data(G_OBJECT(dialog
), "mime_type", type
);
894 gtk_window_set_title(GTK_WINDOW(dialog
), _("Set run action"));
896 tmp
= g_strdup_printf(_("Set default for all `%s/<anything>'"),
898 radio
= gtk_radio_button_new_with_label(NULL
, tmp
);
900 g_object_set_data(G_OBJECT(dialog
), "set_for_all", radio
);
902 tmp
= g_strdup_printf(_("Only for the type `%s/%s'"), type
->media_type
,
904 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), radio
, FALSE
, TRUE
, 0);
905 radio
= gtk_radio_button_new_with_label(
906 gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio
)),
909 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), radio
, FALSE
, TRUE
, 0);
910 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio
), TRUE
);
912 frame
= gtk_frame_new(NULL
);
913 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), frame
, TRUE
, TRUE
, 4);
914 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_IN
);
915 eb
= gtk_event_box_new();
916 gtk_container_add(GTK_CONTAINER(frame
), eb
);
918 gtk_container_set_border_width(GTK_CONTAINER(eb
), 4);
920 handler
= handler_for(type
);
925 link
= readlink_dup(handler
);
930 msg
= g_strdup_printf(_("Currently %s"), link
);
931 gtk_tooltips_set_tip(tooltips
, eb
, msg
, NULL
);
938 gtk_drag_dest_set(eb
, GTK_DEST_DEFAULT_ALL
,
939 targets
, sizeof(targets
) / sizeof(*targets
),
941 g_signal_connect(eb
, "drag_data_received",
942 G_CALLBACK(drag_app_dropped
), dialog
);
944 label
= gtk_label_new(_("Drop a suitable\napplication here"));
945 gtk_misc_set_padding(GTK_MISC(label
), 10, 20);
946 gtk_container_add(GTK_CONTAINER(eb
), label
);
948 hbox
= gtk_hbox_new(FALSE
, 4);
949 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), hbox
, FALSE
, TRUE
, 4);
950 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
951 gtk_box_pack_start(GTK_BOX(hbox
), gtk_label_new(_("OR")),
953 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
955 hbox
= gtk_hbox_new(FALSE
, 4);
956 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), hbox
, FALSE
, TRUE
, 0);
958 label
= gtk_label_new(_("Enter a shell command:")),
959 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
960 gtk_box_pack_start(GTK_BOX(hbox
), label
, TRUE
, TRUE
, 4);
962 gtk_box_pack_start(GTK_BOX(hbox
),
963 new_help_button(show_shell_help
, NULL
), FALSE
, TRUE
, 0);
965 entry
= gtk_entry_new();
966 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), entry
, FALSE
, TRUE
, 0);
967 gtk_widget_grab_focus(entry
);
968 g_object_set_data(G_OBJECT(dialog
), "shell_command", entry
);
969 gtk_entry_set_activates_default(GTK_ENTRY(entry
), TRUE
);
971 /* If possible, fill in the entry box with the current command */
972 tmp
= get_current_command(type
);
975 gtk_entry_set_text(GTK_ENTRY(entry
), tmp
);
976 gtk_editable_set_position(GTK_EDITABLE(entry
), -1);
981 gtk_entry_set_text(GTK_ENTRY(entry
), " \"$1\"");
982 gtk_editable_set_position(GTK_EDITABLE(entry
), 0);
985 gtk_dialog_add_buttons(dialog
,
986 GTK_STOCK_CANCEL
, GTK_RESPONSE_DELETE_EVENT
,
987 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
990 hbox
= gtk_hbox_new(TRUE
, 4);
991 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), hbox
, FALSE
, TRUE
, 0);
993 gtk_dialog_set_default_response(dialog
, GTK_RESPONSE_OK
);
995 g_signal_connect(dialog
, "response",
996 G_CALLBACK(set_action_response
), NULL
);
998 gtk_widget_show_all(GTK_WIDGET(dialog
));
1001 /* The user wants to set a new default action for files of this type.
1002 * Removes the current binding if possible and returns the path to
1003 * save the new one to. NULL means cancel. g_free() the result.
1005 char *get_action_save_path(GtkWidget
*dialog
)
1007 guchar
*path
= NULL
;
1009 guchar
*type_name
= NULL
;
1011 GtkToggleButton
*for_all
;
1013 g_return_val_if_fail(dialog
!= NULL
, NULL
);
1014 type
= g_object_get_data(G_OBJECT(dialog
), "mime_type");
1015 for_all
= g_object_get_data(G_OBJECT(dialog
), "set_for_all");
1016 g_return_val_if_fail(for_all
!= NULL
&& type
!= NULL
, NULL
);
1018 if (gtk_toggle_button_get_active(for_all
))
1019 type_name
= g_strdup(type
->media_type
);
1021 type_name
= g_strconcat(type
->media_type
, "_",
1022 type
->subtype
, NULL
);
1024 path
= choices_find_path_save("", PROJECT
, FALSE
);
1028 _("Choices saving is disabled by CHOICESPATH variable"));
1033 path
= choices_find_path_save(type_name
, "MIME-types", TRUE
);
1035 if (lstat(path
, &info
) == 0)
1037 /* A binding already exists... */
1038 if (S_ISREG(info
.st_mode
) && info
.st_size
> 256)
1040 if (get_choice(PROJECT
,
1041 _("A run action already exists and is quite "
1042 "a big program - are you sure you want to "
1043 "delete it?"), 2, "Cancel", "Delete") != 1)
1053 report_error(_("Can't remove %s: %s"),
1054 path
, g_strerror(errno
));
1066 MIME_type
*mime_type_from_base_type(int base_type
)
1072 case TYPE_DIRECTORY
:
1073 return special_directory
;
1075 return special_pipe
;
1077 return special_socket
;
1078 case TYPE_BLOCK_DEVICE
:
1079 return special_block_dev
;
1080 case TYPE_CHAR_DEVICE
:
1081 return special_char_dev
;
1083 return special_unknown
;
1086 /* Takes the st_mode field from stat() and returns the base type.
1087 * Should not be a symlink.
1089 int mode_to_base_type(int st_mode
)
1091 if (S_ISREG(st_mode
))
1093 else if (S_ISDIR(st_mode
))
1094 return TYPE_DIRECTORY
;
1095 else if (S_ISBLK(st_mode
))
1096 return TYPE_BLOCK_DEVICE
;
1097 else if (S_ISCHR(st_mode
))
1098 return TYPE_CHAR_DEVICE
;
1099 else if (S_ISFIFO(st_mode
))
1101 else if (S_ISSOCK(st_mode
))
1107 /* Returns TRUE is this is something that is run by looking up its type
1108 * in MIME-types and, hence, can have its run action set.
1110 gboolean
can_set_run_action(DirItem
*item
)
1112 g_return_val_if_fail(item
!= NULL
, FALSE
);
1114 return item
->base_type
== TYPE_FILE
&&
1115 !(item
->mime_type
== special_exec
);
1118 /* Open all <Choices>/type directories and display a message */
1119 static void open_choices_dirs(gchar
*type
, gchar
*what
)
1125 dir
= choices_find_path_save("", type
, TRUE
);
1127 list
= choices_list_dirs(type
);
1129 for (i
= list
->len
- 1; i
>= 0; i
--)
1130 filer_opendir(list
->pdata
[i
], NULL
);
1132 choices_free_list(list
);
1135 /* To edit the MIME types, open a filer window for <Choices>/MIME-info */
1136 static void edit_mime_types(guchar
*unused
)
1138 open_choices_dirs("MIME-info", "the files defining MIME types");
1141 static void reread_mime_files(guchar
*unused
)
1146 static GList
*build_type_reread(Option
*none
, xmlNode
*node
, guchar
*label
)
1148 GtkWidget
*button
, *align
;
1150 g_return_val_if_fail(none
== NULL
, NULL
);
1152 align
= gtk_alignment_new(0.1, 0, 0.1, 0);
1153 button
= gtk_button_new_with_label(_(label
));
1154 gtk_container_add(GTK_CONTAINER(align
), button
);
1156 g_signal_connect_swapped(button
, "clicked",
1157 G_CALLBACK(reread_mime_files
), NULL
);
1159 return g_list_append(NULL
, align
);
1162 static GList
*build_type_edit(Option
*none
, xmlNode
*node
, guchar
*label
)
1164 GtkWidget
*button
, *align
;
1166 g_return_val_if_fail(none
== NULL
, NULL
);
1168 align
= gtk_alignment_new(0.1, 0, 0.1, 0);
1169 button
= gtk_button_new_with_label(_(label
));
1170 gtk_container_add(GTK_CONTAINER(align
), button
);
1172 g_signal_connect_swapped(button
, "clicked",
1173 G_CALLBACK(edit_mime_types
), NULL
);
1175 return g_list_append(NULL
, align
);
1178 /* Parse file type colours and allocate/free them as necessary */
1179 static void alloc_type_colours(void)
1181 gboolean success
[NUM_TYPE_COLOURS
];
1182 int change_count
= 0; /* No. needing realloc */
1184 static gboolean allocated
= FALSE
;
1187 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
1189 GdkColor
*c
= &type_colours
[i
];
1191 gushort g
= c
->green
;
1192 gushort b
= c
->blue
;
1194 gdk_color_parse(o_type_colours
[i
].value
, &type_colours
[i
]);
1196 if (allocated
&& (c
->red
!= r
|| c
->green
!= g
|| c
->blue
!= b
))
1200 /* Free colours if they were previously allocated and
1201 * have changed or become unneeded.
1203 if (allocated
&& (change_count
|| !o_display_colour_types
.int_value
))
1205 gdk_colormap_free_colors(gdk_rgb_get_cmap(),
1206 type_colours
, NUM_TYPE_COLOURS
);
1210 /* Allocate colours, unless they are still allocated (=> they didn't
1211 * change) or we don't want them anymore.
1212 * XXX: what should be done if allocation fails?
1214 if (!allocated
&& o_display_colour_types
.int_value
)
1216 gdk_colormap_alloc_colors(gdk_rgb_get_cmap(),
1217 type_colours
, NUM_TYPE_COLOURS
,
1218 FALSE
, TRUE
, success
);
1223 /* Return a pointer to a (static) colour for this item. If colouring is
1224 * off, returns normal.
1226 GdkColor
*type_get_colour(DirItem
*item
, GdkColor
*normal
)
1228 if (!o_display_colour_types
.int_value
)
1231 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
1232 return &type_colours
[8];
1233 else if (item
->flags
& ITEM_FLAG_APPDIR
)
1234 return &type_colours
[9];
1236 return &type_colours
[item
->base_type
];