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 /* Colours for file types (same order as base types) */
68 static gchar
*opt_type_colours
[][2] = {
69 {"display_err_colour", "#ff0000"},
70 {"display_unkn_colour", "#000000"},
71 {"display_dir_colour", "#000080"},
72 {"display_pipe_colour", "#444444"},
73 {"display_sock_colour", "#ff00ff"},
74 {"display_file_colour", "#000000"},
75 {"display_cdev_colour", "#000000"},
76 {"display_bdev_colour", "#000000"},
77 {"display_exec_colour", "#006000"},
78 {"display_adir_colour", "#006000"}
80 #define NUM_TYPE_COLOURS\
81 (sizeof(opt_type_colours) / sizeof(opt_type_colours[0]))
83 /* Parsed colours for file types */
84 static Option o_type_colours
[NUM_TYPE_COLOURS
];
85 static GdkColor type_colours
[NUM_TYPE_COLOURS
];
87 /* Static prototypes */
88 static void alloc_type_colours(void);
89 static char *import_extensions(guchar
*line
);
90 static void import_for_dir(guchar
*path
);
91 char *get_action_save_path(GtkWidget
*dialog
);
92 static void edit_mime_types(guchar
*unused
);
93 static void reread_mime_files(guchar
*unused
);
94 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
);
95 static GList
*build_type_reread(Option
*none
, xmlNode
*node
, guchar
*label
);
96 static GList
*build_type_edit(Option
*none
, xmlNode
*node
, guchar
*label
);
98 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *).
99 * Extensions may contain dots; 'tar.gz' matches '*.tar.gz', etc.
100 * The hash table is consulted from each dot in the string in turn
101 * (First .ps.gz, then try .gz)
103 static GHashTable
*extension_hash
= NULL
;
104 static char *current_type
= NULL
; /* (used while reading file) */
106 static GList
*patterns
= NULL
; /* [(regexp -> MIME type)] */
108 /* Hash of all allocated MIME types, indexed by "media/subtype".
109 * MIME_type structs are never freed; this table prevents memory leaks
110 * when rereading the config files.
112 static GHashTable
*type_hash
= NULL
;
114 /* Most things on Unix are text files, so this is the default type */
115 MIME_type
*text_plain
;
116 MIME_type
*special_directory
;
117 MIME_type
*special_pipe
;
118 MIME_type
*special_socket
;
119 MIME_type
*special_block_dev
;
120 MIME_type
*special_char_dev
;
121 MIME_type
*special_exec
;
122 MIME_type
*special_unknown
;
124 static Option o_display_colour_types
;
131 extension_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
132 type_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
134 text_plain
= get_mime_type("text/plain", TRUE
);
135 special_directory
= get_mime_type("special/directory", TRUE
);
136 special_pipe
= get_mime_type("special/pipe", TRUE
);
137 special_socket
= get_mime_type("special/socket", TRUE
);
138 special_block_dev
= get_mime_type("special/block-device", TRUE
);
139 special_char_dev
= get_mime_type("special/char-device", TRUE
);
140 special_exec
= get_mime_type("special/executable", TRUE
);
141 special_unknown
= get_mime_type("special/unknown", TRUE
);
145 list
= choices_list_dirs("MIME-info");
146 for (i
= list
->len
- 1; i
>= 0; i
--)
147 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
148 choices_free_list(list
);
150 option_register_widget("type-edit", build_type_edit
);
151 option_register_widget("type-reread", build_type_reread
);
153 option_add_int(&o_display_colour_types
, "display_colour_types", TRUE
);
155 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
156 option_add_string(&o_type_colours
[i
],
157 opt_type_colours
[i
][0],
158 opt_type_colours
[i
][1]);
159 alloc_type_colours();
161 option_add_notify(alloc_type_colours
);
164 /* Returns the MIME_type structure for the given type name. It is looked
165 * up in type_hash and returned if found. If not found (and can_create is
166 * TRUE) then a new MIME_type is made, added to type_hash and returned.
167 * NULL is returned if type_name is not in type_hash and can_create is
168 * FALSE, or if type_name does not contain a '/' character.
170 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
)
175 mtype
= g_hash_table_lookup(type_hash
, type_name
);
176 if (mtype
|| !can_create
)
179 slash
= strchr(type_name
, '/');
180 g_return_val_if_fail(slash
!= NULL
, NULL
); /* XXX: Report nicely */
182 mtype
= g_new(MIME_type
, 1);
183 mtype
->media_type
= g_strndup(type_name
, slash
- type_name
);
184 mtype
->subtype
= g_strdup(slash
+ 1);
187 g_hash_table_insert(type_hash
, g_strdup(type_name
), mtype
);
193 static void pattern_delete(gpointer patt
, gpointer udata
)
195 Pattern
*pattern
= (Pattern
*) patt
;
197 regfree(&pattern
->buffer
);
203 static gboolean
extension_delete(gpointer key
, gpointer value
, gpointer udata
)
205 /* key is a g_strdup'ed string */
208 /* value is also preserved in type_hash, so don't delete */
210 return TRUE
; /* Removes this entry */
214 void type_reread(void)
219 g_hash_table_foreach_remove(extension_hash
, extension_delete
, NULL
);
221 g_list_foreach(patterns
, pattern_delete
, NULL
);
222 g_list_free(patterns
);
228 list
= choices_list_dirs("MIME-info");
229 for (i
= list
->len
- 1; i
>= 0; i
--)
230 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
231 choices_free_list(list
);
236 /* Parse every file in 'dir' */
237 static void import_for_dir(guchar
*path
)
246 while ((item
= readdir(dir
)))
251 if (item
->d_name
[0] == '.')
255 file
= make_path(path
, item
->d_name
)->str
;
257 if (stat(file
, &info
) == 0 && S_ISREG(info
.st_mode
))
258 parse_file(file
, import_extensions
);
264 /* Add one entry to the extension_hash table */
265 static void add_ext(char *type_name
, char *ext
)
269 new = get_mime_type(type_name
, TRUE
);
271 g_return_if_fail(new != NULL
);
273 g_hash_table_insert(extension_hash
, g_strdup(ext
), new);
276 static void add_regex(char *type_name
, char *reg
)
283 slash
= strchr(type_name
, '/');
284 g_return_if_fail(slash
!= NULL
); /* XXX: Report nicely */
286 pattern
= g_new0(Pattern
, 1);
288 if (regcomp(&pattern
->buffer
, reg
, REG_EXTENDED
| REG_NOSUB
))
290 regfree(&pattern
->buffer
);
295 new = get_mime_type(type_name
, TRUE
);
297 g_return_if_fail(new != NULL
);
301 patterns
= g_list_prepend(patterns
, pattern
);
305 /* Parse one line from the file and add entries to extension_hash */
306 static char *import_extensions(guchar
*line
)
309 if (*line
== '\0' || *line
== '#')
310 return NULL
; /* Comment */
315 return _("Missing MIME-type");
316 while (*line
&& isspace(*line
))
319 if (strncmp(line
, "ext:", 4) == 0)
326 while (*line
&& isspace(*line
))
331 while (*line
&& !isspace(*line
))
335 add_ext(current_type
, ext
);
338 else if (strncmp(line
, "regex:", 6) == 0)
342 while (*line
&& isspace(*line
))
345 add_regex(current_type
, line
);
352 while (*line
&& *line
!= ':' && !isspace(*line
))
356 while (*line
&& isspace(*line
))
359 return _("Trailing chars after MIME-type");
360 current_type
= g_strdup(type
);
365 char *basetype_name(DirItem
*item
)
367 if (item
->flags
& ITEM_FLAG_SYMLINK
)
368 return _("Sym link");
369 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
370 return _("Mount point");
371 else if (item
->flags
& ITEM_FLAG_APPDIR
)
374 switch (item
->base_type
)
380 case TYPE_CHAR_DEVICE
:
381 return _("Char dev");
382 case TYPE_BLOCK_DEVICE
:
383 return _("Block dev");
393 /* MIME-type guessing */
395 /* Get the type of this file - stats the file and uses that if
396 * possible. For regular or missing files, uses the pathname.
398 MIME_type
*type_get_type(guchar
*path
)
401 MIME_type
*type
= NULL
;
402 int base
= TYPE_FILE
;
403 gboolean exec
= FALSE
;
405 if (mc_stat(path
, &info
) == 0)
407 base
= mode_to_base_type(info
.st_mode
);
408 if (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))
412 if (base
== TYPE_FILE
)
413 type
= type_from_path(path
);
417 if (base
== TYPE_FILE
&& exec
)
420 type
= mime_type_from_base_type(base
);
426 /* Returns a pointer to the MIME-type.
427 * NULL if we can't think of anything.
429 MIME_type
*type_from_path(char *path
)
431 char *ext
, *dot
, *lower
, *leafname
;
437 leafname
= strrchr(path
, '/');
444 while ((dot
= strchr(ext
, '.')))
450 type
= g_hash_table_lookup(extension_hash
, ext
);
455 lower
= g_strdup(ext
);
457 type
= g_hash_table_lookup(extension_hash
, lower
);
465 len
= strlen(leafname
);
467 for (patt
= patterns
; patt
; patt
= patt
->next
)
469 Pattern
*pattern
= (Pattern
*) patt
->data
;
471 if (regexec(&pattern
->buffer
, leafname
, 0, NULL
, 0) == 0)
472 return pattern
->type
;
479 /* Returns the file/dir in Choices for handling this type.
480 * NULL if there isn't one. g_free() the result.
482 static char *handler_for(MIME_type
*type
)
487 type_name
= g_strconcat(type
->media_type
, "_", type
->subtype
, NULL
);
488 open
= choices_find_path_load(type_name
, "MIME-types");
492 open
= choices_find_path_load(type
->media_type
, "MIME-types");
497 /* Actions for types */
499 gboolean
type_open(char *path
, MIME_type
*type
)
501 char *argv
[] = {NULL
, NULL
, NULL
};
508 open
= handler_for(type
);
512 if (stat(open
, &info
))
514 report_error("stat(%s): %s", open
, g_strerror(errno
));
519 if (S_ISDIR(info
.st_mode
))
520 argv
[0] = g_strconcat(open
, "/AppRun", NULL
);
524 retval
= rox_spawn(home_dir
, argv
);
534 /* Return the image for this type, loading it if needed.
535 * Places to check are: (eg type="text_plain", base="text")
536 * 1. Choices:MIME-icons/<type>
537 * 2. Choices:MIME-icons/<base>
538 * 3. Unknown type icon.
540 * Note: You must pixmap_unref() the image afterwards.
542 MaskedPixmap
*type_to_icon(MIME_type
*type
)
550 pixmap_ref(im_unknown
);
555 /* Already got an image? */
558 /* Yes - don't recheck too often */
559 if (abs(now
- type
->image_time
) < 2)
561 pixmap_ref(type
->image
);
564 pixmap_unref(type
->image
);
568 type_name
= g_strconcat(type
->media_type
, "_",
569 type
->subtype
, ".xpm", NULL
);
570 path
= choices_find_path_load(type_name
, "MIME-icons");
573 strcpy(type_name
+ strlen(type
->media_type
), ".xpm");
574 path
= choices_find_path_load(type_name
, "MIME-icons");
581 type
->image
= g_fscache_lookup(pixmap_cache
, path
);
587 /* One ref from the type structure, one returned */
588 type
->image
= im_unknown
;
589 pixmap_ref(im_unknown
);
592 type
->image_time
= now
;
594 pixmap_ref(type
->image
);
598 GdkAtom
type_to_atom(MIME_type
*type
)
603 g_return_val_if_fail(type
!= NULL
, GDK_NONE
);
605 str
= g_strconcat(type
->media_type
, "/", type
->subtype
, NULL
);
606 retval
= gdk_atom_intern(str
, FALSE
);
612 void show_shell_help(gpointer data
)
614 report_error(_("Enter a shell command which will load \"$1\" into "
615 "a suitable program. Eg:\n\n"
619 /* Called if the user clicks on the OK button */
620 static void set_shell_action(GtkWidget
*dialog
)
623 GtkToggleButton
*for_all
;
624 guchar
*command
, *path
, *tmp
;
628 entry
= gtk_object_get_data(GTK_OBJECT(dialog
), "shell_command");
629 for_all
= gtk_object_get_data(GTK_OBJECT(dialog
), "set_for_all");
630 g_return_if_fail(entry
!= NULL
);
632 command
= gtk_entry_get_text(entry
);
634 if (!strchr(command
, '$'))
636 show_shell_help(NULL
);
640 path
= get_action_save_path(dialog
);
644 tmp
= g_strdup_printf("#! /bin/sh\nexec %s\n", command
);
647 file
= fopen(path
, "wb");
648 if (fwrite(tmp
, 1, len
, file
) < len
)
650 if (fclose(file
) && error
== 0)
652 if (chmod(path
, 0777))
656 report_error(g_strerror(errno
));
661 gtk_widget_destroy(dialog
);
664 /* Called when a URI list is dropped onto the box in the Set Run Action
665 * dialog. Make sure it's an application, and make that the default
668 void drag_app_dropped(GtkWidget
*eb
,
669 GdkDragContext
*context
,
672 GtkSelectionData
*selection_data
,
681 if (!selection_data
->data
)
682 return; /* Timeout? */
684 uris
= uri_list_to_glist(selection_data
->data
);
686 if (g_list_length(uris
) == 1)
687 app
= get_local_path((guchar
*) uris
->data
);
693 _("You should drop a single (local) application "
694 "onto the drop box - that application will be "
695 "used to load files of this type in future"));
699 item
= diritem_new(NULL
);
700 diritem_restat(app
, item
);
701 if (item
->flags
& (ITEM_FLAG_APPDIR
| ITEM_FLAG_EXEC_FILE
))
705 path
= get_action_save_path(dialog
);
709 if (symlink(app
, path
))
710 delayed_error("symlink: %s",
713 destroy_on_idle(dialog
);
720 _("This is not a program! Give me an application "
726 /* Find the current command which is used to run files of this type.
727 * Returns NULL on failure. g_free() the result.
729 static guchar
*get_current_command(MIME_type
*type
)
732 char *handler
, *nl
, *data
= NULL
;
734 guchar
*command
= NULL
;
736 handler
= handler_for(type
);
739 return NULL
; /* No current handler */
741 if (stat(handler
, &info
))
742 goto out
; /* Can't stat */
744 if ((!S_ISREG(info
.st_mode
)) || info
.st_size
> 256)
745 goto out
; /* Only use small regular files */
747 if (!load_file(handler
, &data
, &len
))
748 goto out
; /* Didn't load OK */
750 if (strncmp(data
, "#! /bin/sh\nexec ", 16) != 0)
751 goto out
; /* Not one of ours */
753 nl
= strchr(data
+ 16, '\n');
755 goto out
; /* No newline! */
757 command
= g_strndup(data
+ 16, nl
- data
- 16);
764 /* Find the current command which is used to run files of this type,
765 * and return a textual description of it.
766 * g_free() the result.
768 gchar
*describe_current_command(MIME_type
*type
)
775 g_return_val_if_fail(type
!= NULL
, NULL
);
777 if (type
== special_exec
)
778 return g_strdup(_("Execute file"));
780 handler
= handler_for(type
);
783 return g_strdup(_("No run action defined"));
785 target
= readlink_dup(handler
);
788 /* Cope with relative paths (shouldn't normally be needed) */
790 if (target
[0] == '/')
799 dir
= g_dirname(handler
);
801 handler
= g_strconcat(dir
, "/", target
, NULL
);
807 if (mc_stat(handler
, &info
) !=0 )
809 desc
= g_strdup_printf(_("Error in handler %s: %s"), handler
,
814 if (S_ISDIR(info
.st_mode
))
817 uid_t dir_uid
= info
.st_uid
;
819 tmp
= make_path(handler
, "AppRun")->str
;
821 if (mc_lstat(tmp
, &info
) != 0 || info
.st_uid
!= dir_uid
822 || !(info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
823 desc
= g_strdup_printf(
824 _("Invalid application %s (bad AppRun)"),
826 /* Else, just report handler... */
831 /* It's not an application directory, and it's not a symlink... */
833 if (access(handler
, X_OK
) != 0)
835 desc
= g_strdup_printf(_("Non-executable %s"), handler
);
839 desc
= get_current_command(type
);
849 /* Display a dialog box allowing the user to set the default run action
852 void type_set_handler_dialog(MIME_type
*type
)
856 GtkWidget
*dialog
, *vbox
, *frame
, *hbox
, *entry
, *label
, *button
;
857 GtkWidget
*radio
, *eb
;
858 GtkTargetEntry targets
[] = {
859 {"text/uri-list", 0, TARGET_URI_LIST
},
862 g_return_if_fail(type
!= NULL
);
864 dialog
= gtk_window_new(GTK_WINDOW_DIALOG
);
866 gtk_window_set_type_hint(GTK_WINDOW(dialog
),
867 GDK_WINDOW_TYPE_HINT_DIALOG
);
869 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
870 gtk_object_set_data(GTK_OBJECT(dialog
), "mime_type", type
);
872 gtk_window_set_title(GTK_WINDOW(dialog
), _("Set run action"));
873 gtk_container_set_border_width(GTK_CONTAINER(dialog
), 10);
875 vbox
= gtk_vbox_new(FALSE
, 4);
876 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
878 tmp
= g_strdup_printf(_("Set default for all `%s/<anything>'"),
880 radio
= gtk_radio_button_new_with_label(NULL
, tmp
);
882 gtk_object_set_data(GTK_OBJECT(dialog
), "set_for_all", radio
);
884 tmp
= g_strdup_printf(_("Only for the type `%s/%s'"), type
->media_type
,
886 gtk_box_pack_start(GTK_BOX(vbox
), radio
, FALSE
, TRUE
, 0);
887 radio
= gtk_radio_button_new_with_label(
888 gtk_radio_button_group(GTK_RADIO_BUTTON(radio
)),
891 gtk_box_pack_start(GTK_BOX(vbox
), radio
, FALSE
, TRUE
, 0);
892 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio
), TRUE
);
894 frame
= gtk_frame_new(NULL
);
895 gtk_box_pack_start(GTK_BOX(vbox
), frame
, TRUE
, TRUE
, 4);
896 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_IN
);
897 eb
= gtk_event_box_new();
898 gtk_container_add(GTK_CONTAINER(frame
), eb
);
900 gtk_container_set_border_width(GTK_CONTAINER(eb
), 4);
902 handler
= handler_for(type
);
907 link
= readlink_dup(handler
);
912 msg
= g_strdup_printf(_("Currently %s"), link
);
913 gtk_tooltips_set_tip(tooltips
, eb
, msg
, NULL
);
920 gtk_drag_dest_set(eb
, GTK_DEST_DEFAULT_ALL
,
921 targets
, sizeof(targets
) / sizeof(*targets
),
923 gtk_signal_connect(GTK_OBJECT(eb
), "drag_data_received",
924 GTK_SIGNAL_FUNC(drag_app_dropped
), dialog
);
926 label
= gtk_label_new(_("Drop a suitable\napplication here"));
927 gtk_misc_set_padding(GTK_MISC(label
), 10, 20);
928 gtk_container_add(GTK_CONTAINER(eb
), label
);
930 hbox
= gtk_hbox_new(FALSE
, 4);
931 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 4);
932 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
933 gtk_box_pack_start(GTK_BOX(hbox
), gtk_label_new(_("OR")),
935 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
937 hbox
= gtk_hbox_new(FALSE
, 4);
938 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
940 label
= gtk_label_new(_("Enter a shell command:")),
941 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
942 gtk_box_pack_start(GTK_BOX(hbox
), label
, TRUE
, TRUE
, 4);
944 gtk_box_pack_start(GTK_BOX(hbox
),
945 new_help_button(show_shell_help
, NULL
), FALSE
, TRUE
, 0);
947 entry
= gtk_entry_new();
948 gtk_box_pack_start(GTK_BOX(vbox
), entry
, FALSE
, TRUE
, 0);
949 gtk_widget_grab_focus(entry
);
950 gtk_object_set_data(GTK_OBJECT(dialog
), "shell_command", entry
);
951 gtk_signal_connect_object(GTK_OBJECT(entry
), "activate",
952 GTK_SIGNAL_FUNC(set_shell_action
), GTK_OBJECT(dialog
));
954 hbox
= gtk_hbox_new(TRUE
, 4);
955 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
957 /* If possible, fill in the entry box with the current command */
958 tmp
= get_current_command(type
);
961 gtk_entry_set_text(GTK_ENTRY(entry
), tmp
);
962 gtk_entry_set_position(GTK_ENTRY(entry
), -1);
967 gtk_entry_set_text(GTK_ENTRY(entry
), " \"$1\"");
968 gtk_entry_set_position(GTK_ENTRY(entry
), 0);
971 button
= gtk_button_new_with_label(_("OK"));
972 gtk_box_pack_start(GTK_BOX(hbox
), button
, TRUE
, TRUE
, 0);
973 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
974 gtk_window_set_default(GTK_WINDOW(dialog
), button
);
975 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
976 GTK_SIGNAL_FUNC(set_shell_action
), GTK_OBJECT(dialog
));
978 button
= gtk_button_new_with_label(_("Cancel"));
979 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
980 gtk_box_pack_start(GTK_BOX(hbox
), button
, TRUE
, TRUE
, 0);
981 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
982 GTK_SIGNAL_FUNC(gtk_widget_destroy
),
985 gtk_widget_show_all(dialog
);
988 /* The user wants to set a new default action for files of this type.
989 * Removes the current binding if possible and returns the path to
990 * save the new one to. NULL means cancel. g_free() the result.
992 char *get_action_save_path(GtkWidget
*dialog
)
996 guchar
*type_name
= NULL
;
998 GtkToggleButton
*for_all
;
1000 g_return_val_if_fail(dialog
!= NULL
, NULL
);
1001 type
= gtk_object_get_data(GTK_OBJECT(dialog
), "mime_type");
1002 for_all
= gtk_object_get_data(GTK_OBJECT(dialog
), "set_for_all");
1003 g_return_val_if_fail(for_all
!= NULL
&& type
!= NULL
, NULL
);
1005 if (gtk_toggle_button_get_active(for_all
))
1006 type_name
= g_strdup(type
->media_type
);
1008 type_name
= g_strconcat(type
->media_type
, "_",
1009 type
->subtype
, NULL
);
1011 path
= choices_find_path_save("", PROJECT
, FALSE
);
1015 _("Choices saving is disabled by CHOICESPATH variable"));
1020 path
= choices_find_path_save(type_name
, "MIME-types", TRUE
);
1022 if (lstat(path
, &info
) == 0)
1024 /* A binding already exists... */
1025 if (S_ISREG(info
.st_mode
) && info
.st_size
> 256)
1027 if (get_choice(PROJECT
,
1028 _("A run action already exists and is quite "
1029 "a big program - are you sure you want to "
1030 "delete it?"), 2, "Cancel", "Delete") != 1)
1040 report_error(_("Can't remove %s: %s"),
1041 path
, g_strerror(errno
));
1053 MIME_type
*mime_type_from_base_type(int base_type
)
1059 case TYPE_DIRECTORY
:
1060 return special_directory
;
1062 return special_pipe
;
1064 return special_socket
;
1065 case TYPE_BLOCK_DEVICE
:
1066 return special_block_dev
;
1067 case TYPE_CHAR_DEVICE
:
1068 return special_char_dev
;
1070 return special_unknown
;
1073 /* Takes the st_mode field from stat() and returns the base type.
1074 * Should not be a symlink.
1076 int mode_to_base_type(int st_mode
)
1078 if (S_ISREG(st_mode
))
1080 else if (S_ISDIR(st_mode
))
1081 return TYPE_DIRECTORY
;
1082 else if (S_ISBLK(st_mode
))
1083 return TYPE_BLOCK_DEVICE
;
1084 else if (S_ISCHR(st_mode
))
1085 return TYPE_CHAR_DEVICE
;
1086 else if (S_ISFIFO(st_mode
))
1088 else if (S_ISSOCK(st_mode
))
1094 /* Returns TRUE is this is something that is run by looking up its type
1095 * in MIME-types and, hence, can have its run action set.
1097 gboolean
can_set_run_action(DirItem
*item
)
1099 g_return_val_if_fail(item
!= NULL
, FALSE
);
1101 return item
->base_type
== TYPE_FILE
&&
1102 !(item
->mime_type
== special_exec
);
1105 /* Open all <Choices>/type directories and display a message */
1106 static void open_choices_dirs(gchar
*type
, gchar
*what
)
1112 dir
= choices_find_path_save("", type
, TRUE
);
1114 list
= choices_list_dirs(type
);
1116 for (i
= list
->len
- 1; i
>= 0; i
--)
1117 filer_opendir(list
->pdata
[i
], NULL
);
1119 choices_free_list(list
);
1122 /* To edit the MIME types, open a filer window for <Choices>/MIME-info */
1123 static void edit_mime_types(guchar
*unused
)
1125 open_choices_dirs("MIME-info", "the files defining MIME types");
1128 static void reread_mime_files(guchar
*unused
)
1133 static GList
*build_type_reread(Option
*none
, xmlNode
*node
, guchar
*label
)
1135 GtkWidget
*button
, *align
;
1137 g_return_val_if_fail(none
== NULL
, NULL
);
1139 align
= gtk_alignment_new(0.1, 0, 0.1, 0);
1140 button
= gtk_button_new_with_label(_(label
));
1141 gtk_container_add(GTK_CONTAINER(align
), button
);
1143 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
1144 GTK_SIGNAL_FUNC(reread_mime_files
), NULL
);
1146 return g_list_append(NULL
, align
);
1149 static GList
*build_type_edit(Option
*none
, xmlNode
*node
, guchar
*label
)
1151 GtkWidget
*button
, *align
;
1153 g_return_val_if_fail(none
== NULL
, NULL
);
1155 align
= gtk_alignment_new(0.1, 0, 0.1, 0);
1156 button
= gtk_button_new_with_label(_(label
));
1157 gtk_container_add(GTK_CONTAINER(align
), button
);
1159 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
1160 GTK_SIGNAL_FUNC(edit_mime_types
), NULL
);
1162 return g_list_append(NULL
, align
);
1165 /* Parse file type colours and allocate/free them as necessary */
1166 static void alloc_type_colours(void)
1168 gboolean success
[NUM_TYPE_COLOURS
];
1169 int change_count
= 0; /* No. needing realloc */
1171 static gboolean allocated
= FALSE
;
1174 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
1176 GdkColor
*c
= &type_colours
[i
];
1178 gushort g
= c
->green
;
1179 gushort b
= c
->blue
;
1181 gdk_color_parse(o_type_colours
[i
].value
, &type_colours
[i
]);
1183 if (allocated
&& (c
->red
!= r
|| c
->green
!= g
|| c
->blue
!= b
))
1187 /* Free colours if they were previously allocated and
1188 * have changed or become unneeded.
1190 if (allocated
&& (change_count
|| !o_display_colour_types
.int_value
))
1192 gdk_colormap_free_colors(gdk_rgb_get_cmap(),
1193 type_colours
, NUM_TYPE_COLOURS
);
1197 /* Allocate colours, unless they are still allocated (=> they didn't
1198 * change) or we don't want them anymore.
1199 * XXX: what should be done if allocation fails?
1201 if (!allocated
&& o_display_colour_types
.int_value
)
1203 gdk_colormap_alloc_colors(gdk_rgb_get_cmap(),
1204 type_colours
, NUM_TYPE_COLOURS
,
1205 FALSE
, TRUE
, success
);
1210 /* Return a pointer to a (static) colour for this item. If colouring is
1211 * off, returns normal.
1213 GdkColor
*type_get_colour(DirItem
*item
, GdkColor
*normal
)
1215 if (!o_display_colour_types
.int_value
)
1218 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
1219 return &type_colours
[8];
1220 else if (item
->flags
& ITEM_FLAG_APPDIR
)
1221 return &type_colours
[9];
1223 return &type_colours
[item
->base_type
];