2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* type.c - code for dealing with filetypes */
29 #include <sys/param.h>
31 #include <sys/types.h>
35 # include <libgnomevfs/gnome-vfs.h>
36 # include <libgnomevfs/gnome-vfs-mime.h>
37 # include <libgnomevfs/gnome-vfs-mime-handlers.h>
38 # include <libgnomevfs/gnome-vfs-application-registry.h>
48 #include "gui_support.h"
56 #include "action.h" /* (for action_chmod) */
63 #define TYPE_NS "http://www.freedesktop.org/standards/shared-mime-info"
64 enum {SET_MEDIA
, SET_TYPE
};
66 /* Colours for file types (same order as base types) */
67 static gchar
*opt_type_colours
[][2] = {
68 {"display_err_colour", "#ff0000"},
69 {"display_unkn_colour", "#000000"},
70 {"display_dir_colour", "#000080"},
71 {"display_pipe_colour", "#444444"},
72 {"display_sock_colour", "#ff00ff"},
73 {"display_file_colour", "#000000"},
74 {"display_cdev_colour", "#000000"},
75 {"display_bdev_colour", "#000000"},
76 {"display_door_colour", "#ff00ff"},
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 void options_changed(void);
90 static char *get_action_save_path(GtkWidget
*dialog
);
91 static MIME_type
*get_mime_type(const gchar
*type_name
, gboolean can_create
);
92 static gboolean
remove_handler_with_confirm(const guchar
*path
);
93 static void set_icon_theme(void);
94 static GList
*build_icon_theme(Option
*option
, xmlNode
*node
, guchar
*label
);
96 /* Hash of all allocated MIME types, indexed by "media/subtype".
97 * MIME_type structs are never freed; this table prevents memory leaks
98 * when rereading the config files.
100 static GHashTable
*type_hash
= NULL
;
102 /* Most things on Unix are text files, so this is the default type */
103 MIME_type
*text_plain
;
104 MIME_type
*inode_directory
;
105 MIME_type
*inode_mountpoint
;
106 MIME_type
*inode_pipe
;
107 MIME_type
*inode_socket
;
108 MIME_type
*inode_block_dev
;
109 MIME_type
*inode_char_dev
;
110 MIME_type
*application_executable
;
111 MIME_type
*application_octet_stream
;
112 MIME_type
*application_x_shellscript
;
113 MIME_type
*application_x_desktop
;
114 MIME_type
*inode_unknown
;
115 MIME_type
*inode_door
;
117 static Option o_display_colour_types
;
118 static Option o_icon_theme
;
120 static GtkIconTheme
*icon_theme
= NULL
;
121 static GtkIconTheme
*rox_theme
= NULL
;
122 static GtkIconTheme
*gnome_theme
= NULL
;
128 icon_theme
= gtk_icon_theme_new();
130 type_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
132 text_plain
= get_mime_type("text/plain", TRUE
);
133 inode_directory
= get_mime_type("inode/directory", TRUE
);
134 inode_mountpoint
= get_mime_type("inode/mount-point", TRUE
);
135 inode_pipe
= get_mime_type("inode/fifo", TRUE
);
136 inode_socket
= get_mime_type("inode/socket", TRUE
);
137 inode_block_dev
= get_mime_type("inode/blockdevice", TRUE
);
138 inode_char_dev
= get_mime_type("inode/chardevice", TRUE
);
139 application_executable
= get_mime_type("application/x-executable", TRUE
);
140 application_octet_stream
= get_mime_type("application/octet-stream", TRUE
);
141 application_x_shellscript
= get_mime_type("application/x-shellscript", TRUE
);
142 application_x_desktop
= get_mime_type("application/x-desktop", TRUE
);
143 application_x_desktop
->executable
= TRUE
;
144 inode_unknown
= get_mime_type("inode/unknown", TRUE
);
145 inode_door
= get_mime_type("inode/door", TRUE
);
147 option_add_string(&o_icon_theme
, "icon_theme", "ROX");
148 option_add_int(&o_display_colour_types
, "display_colour_types", TRUE
);
149 option_register_widget("icon-theme-chooser", build_icon_theme
);
151 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
152 option_add_string(&o_type_colours
[i
],
153 opt_type_colours
[i
][0],
154 opt_type_colours
[i
][1]);
155 alloc_type_colours();
159 option_add_notify(options_changed
);
162 /* Read-load all the glob patterns.
163 * Note: calls filer_update_all.
165 void reread_mime_files(void)
167 gtk_icon_theme_rescan_if_needed(icon_theme
);
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
, '/');
192 g_warning("MIME type '%s' does not contain a '/' character!",
197 mtype
= g_new(MIME_type
, 1);
198 mtype
->media_type
= g_strndup(type_name
, slash
- type_name
);
199 mtype
->subtype
= g_strdup(slash
+ 1);
201 mtype
->comment
= NULL
;
203 mtype
->executable
= xdg_mime_mime_type_subclass(type_name
,
204 "application/x-executable");
206 g_hash_table_insert(type_hash
, g_strdup(type_name
), mtype
);
211 const char *basetype_name(DirItem
*item
)
213 if (item
->flags
& ITEM_FLAG_SYMLINK
)
214 return _("Sym link");
215 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
216 return _("Mount point");
217 else if (item
->flags
& ITEM_FLAG_APPDIR
)
220 switch (item
->base_type
)
226 case TYPE_CHAR_DEVICE
:
227 return _("Char dev");
228 case TYPE_BLOCK_DEVICE
:
229 return _("Block dev");
243 gboolean only_regular
;
246 static void append_names(gpointer key
, gpointer value
, gpointer udata
)
248 struct mime_list
*mlist
= (struct mime_list
*) udata
;
250 if(!mlist
->only_regular
|| strncmp((char *)key
, "inode/", 6)!=0)
251 mlist
->list
= g_list_prepend(mlist
->list
, key
);
254 /* Return list of all mime type names. Caller must free the list
255 * but NOT the strings it contains (which are never freed).
256 If only_regular is true then inode types are excluded.
258 GList
*mime_type_name_list(gboolean only_regular
)
260 struct mime_list list
;
263 list
.only_regular
=only_regular
;
265 g_hash_table_foreach(type_hash
, append_names
, &list
);
266 list
.list
= g_list_sort(list
.list
, (GCompareFunc
) strcmp
);
271 /* MIME-type guessing */
273 /* Get the type of this file - stats the file and uses that if
274 * possible. For regular or missing files, uses the pathname.
276 MIME_type
*type_get_type(const guchar
*path
)
279 MIME_type
*type
= NULL
;
281 item
= diritem_new("");
282 diritem_restat(path
, item
, NULL
);
283 if (item
->base_type
!= TYPE_ERROR
)
284 type
= item
->mime_type
;
290 type
= type_from_path(path
);
298 /* Returns a pointer to the MIME-type.
300 * Tries all enabled methods:
301 * - Look for extended attribute
302 * - If no attribute, check file name
303 * - If no name rule, check contents
305 * NULL if we can't think of anything.
307 MIME_type
*type_from_path(const char *path
)
309 MIME_type
*mime_type
= NULL
;
310 const char *type_name
;
312 /* Check for extended attribute first */
313 mime_type
= xtype_get(path
);
317 /* Try name and contents next */
318 type_name
= xdg_mime_get_mime_type_for_file(path
, NULL
);
320 return get_mime_type(type_name
, TRUE
);
325 /* Returns the file/dir in Choices for handling this type.
326 * NULL if there isn't one. g_free() the result.
328 char *handler_for(MIME_type
*type
)
334 type_name
= g_strconcat(type
->media_type
, "_", type
->subtype
, NULL
);
335 open
= choices_find_xdg_path_load(type_name
, "MIME-types", SITE
);
339 open
= choices_find_xdg_path_load(type
->media_type
,
345 /* Some programs behave differently depending on the command
346 * name (e.g., 'vim' vs 'gvim'), so symlinks need to be followed here.
348 target
= readlink_dup(open
);
354 if (target
[0] == '/')
362 /* Relative path (shouldn't normally be needed) */
366 dir
= g_path_get_dirname(open
);
369 abs_path
= g_strconcat(dir
, "/", target
, NULL
);
377 MIME_type
*mime_type_lookup(const char *type
)
379 return get_mime_type(type
, TRUE
);
382 static void init_aux_theme(GtkIconTheme
**ptheme
, const char *name
)
386 *ptheme
= gtk_icon_theme_new();
387 gtk_icon_theme_set_custom_theme(*ptheme
, name
);
390 inline static void init_rox_theme(void)
392 init_aux_theme(&rox_theme
, "ROX");
395 inline static void init_gnome_theme(void)
397 init_aux_theme(&gnome_theme
, "gnome");
400 /* We don't want ROX to override configured theme so try all possibilities
401 * in icon_theme first */
402 static GtkIconInfo
*mime_type_lookup_icon_info(GtkIconTheme
*theme
,
405 char *type_name
= g_strconcat(type
->media_type
, "-", type
->subtype
, NULL
);
406 GtkIconInfo
*full
= gtk_icon_theme_lookup_icon(theme
, type_name
, HUGE_HEIGHT
, 0);
411 /* Ugly hack... try for a GNOME icon */
412 if (type
== inode_directory
)
413 type_name
= g_strdup("gnome-fs-directory");
415 type_name
= g_strconcat("gnome-mime-", type
->media_type
,
416 "-", type
->subtype
, NULL
);
417 full
= gtk_icon_theme_lookup_icon(theme
, type_name
, HUGE_HEIGHT
, 0);
422 /* Try for a media type */
423 type_name
= g_strconcat(type
->media_type
, "-x-generic", NULL
);
424 full
= gtk_icon_theme_lookup_icon(theme
, type_name
, HUGE_HEIGHT
, 0);
429 /* Ugly hack... try for a GNOME default media icon */
430 type_name
= g_strconcat("gnome-mime-", type
->media_type
, NULL
);
432 full
= gtk_icon_theme_lookup_icon(theme
, type_name
, HUGE_HEIGHT
, 0);
438 /* Actions for types */
440 /* Return the image for this type, loading it if needed.
441 * Places to check are: (eg type="text_plain", base="text")
442 * 1. <Choices>/MIME-icons/base_subtype
443 * 2. Icon theme 'mime-base:subtype'
444 * 3. Icon theme 'mime-base'
445 * 4. Unknown type icon.
447 * Special case: If an icon cannot be found for inode/mount-point, the icon for
448 * inode/directory will be returned (if possible).
450 * Note: You must g_object_unref() the image afterwards.
452 MaskedPixmap
*type_to_icon(MIME_type
*type
)
455 char *type_name
, *path
;
460 g_object_ref(im_unknown
);
465 /* Already got an image? */
468 /* Yes - don't recheck too often */
469 if (abs(now
- type
->image_time
) < 2)
471 g_object_ref(type
->image
);
474 g_object_unref(type
->image
);
479 type_name
= g_strconcat(type
->media_type
, "_", type
->subtype
,
481 path
= choices_find_xdg_path_load(type_name
, "MIME-icons", SITE
);
485 type
->image
= g_fscache_lookup(pixmap_cache
, path
);
492 full
= mime_type_lookup_icon_info(icon_theme
, type
);
493 if (!full
&& icon_theme
!= rox_theme
)
496 full
= mime_type_lookup_icon_info(rox_theme
, type
);
498 if (!full
&& icon_theme
!= gnome_theme
)
501 full
= mime_type_lookup_icon_info(gnome_theme
, type
);
503 if (!full
&& type
== inode_mountpoint
)
505 /* Try to use the inode/directory icon for inode/mount-point */
506 type
= inode_directory
;
511 const char *icon_path
;
512 /* Get the actual icon through our cache, not through GTK, because
513 * GTK doesn't cache icons.
515 icon_path
= gtk_icon_info_get_filename(full
);
516 if (icon_path
!= NULL
)
517 type
->image
= g_fscache_lookup(pixmap_cache
, icon_path
);
518 /* else shouldn't happen, because we didn't use
519 * GTK_ICON_LOOKUP_USE_BUILTIN.
521 gtk_icon_info_free(full
);
527 /* One ref from the type structure, one returned */
528 type
->image
= im_unknown
;
529 g_object_ref(im_unknown
);
532 type
->image_time
= now
;
534 g_object_ref(type
->image
);
538 GdkAtom
type_to_atom(MIME_type
*type
)
543 g_return_val_if_fail(type
!= NULL
, GDK_NONE
);
545 str
= g_strconcat(type
->media_type
, "/", type
->subtype
, NULL
);
546 retval
= gdk_atom_intern(str
, FALSE
);
552 static void show_shell_help(gpointer data
)
554 info_message(_("Enter a shell command which will load \"$@\" into "
555 "a suitable program. Eg:\n\n"
559 /* Called if the user clicks on the OK button. Returns FALSE if an error
560 * was displayed instead of performing the action.
562 static gboolean
set_shell_action(GtkWidget
*dialog
)
565 const guchar
*command
;
570 entry
= g_object_get_data(G_OBJECT(dialog
), "shell_command");
572 g_return_val_if_fail(entry
!= NULL
, FALSE
);
574 command
= gtk_entry_get_text(entry
);
576 if (!strchr(command
, '$'))
578 show_shell_help(NULL
);
582 path
= get_action_save_path(dialog
);
586 tmp
= g_strdup_printf("#! /bin/sh\nexec %s\n", command
);
589 fd
= open(path
, O_CREAT
| O_WRONLY
, 0755);
596 file
= fdopen(fd
, "w");
599 if (fwrite(tmp
, 1, len
, file
) < len
)
601 if (fclose(file
) && error
== 0)
609 report_error(g_strerror(error
));
614 gtk_widget_destroy(dialog
);
619 static void set_action_response(GtkWidget
*dialog
, gint response
, gpointer data
)
621 if (response
== GTK_RESPONSE_OK
)
622 if (!set_shell_action(dialog
))
624 gtk_widget_destroy(dialog
);
627 /* Return the path of the file in choices that handles this type and
629 * NULL if nothing is defined for it.
631 static guchar
*handler_for_radios(GObject
*dialog
)
636 radios
= g_object_get_data(G_OBJECT(dialog
), "rox-radios");
637 type
= g_object_get_data(G_OBJECT(dialog
), "mime_type");
639 g_return_val_if_fail(radios
!= NULL
, NULL
);
640 g_return_val_if_fail(type
!= NULL
, NULL
);
642 switch (radios_get_value(radios
))
645 return choices_find_xdg_path_load(type
->media_type
,
649 gchar
*tmp
, *handler
;
650 tmp
= g_strconcat(type
->media_type
, "_",
651 type
->subtype
, NULL
);
652 handler
= choices_find_xdg_path_load(tmp
,
659 g_warning("Bad type");
664 /* (radios can be NULL if called from clear_run_action) */
665 static void run_action_update(Radios
*radios
, gpointer data
)
669 GObject
*dialog
= G_OBJECT(data
);
671 drop_box
= g_object_get_data(dialog
, "rox-dropbox");
673 g_return_if_fail(drop_box
!= NULL
);
675 handler
= handler_for_radios(dialog
);
681 handler
= readlink_dup(old
);
688 drop_box_set_path(DROP_BOX(drop_box
), handler
);
692 static void clear_run_action(GtkWidget
*drop_box
, GtkWidget
*dialog
)
696 handler
= handler_for_radios(G_OBJECT(dialog
));
699 remove_handler_with_confirm(handler
);
701 run_action_update(NULL
, dialog
);
704 /* Called when a URI list is dropped onto the box in the Set Run Action
705 * dialog. Make sure it's an application, and make that the default
708 static void drag_app_dropped(GtkWidget
*drop_box
,
714 item
= diritem_new("");
715 diritem_restat(app
, item
, NULL
);
716 if (item
->flags
& ITEM_FLAG_APPDIR
|| EXECUTABLE_FILE(item
))
720 path
= get_action_save_path(dialog
);
724 if (symlink(app
, path
))
725 delayed_error("symlink: %s",
728 destroy_on_idle(dialog
);
735 _("This is not a program! Give me an application "
741 /* Find the current command which is used to run files of this type.
742 * Returns NULL on failure. g_free() the result.
744 static guchar
*get_current_command(MIME_type
*type
)
747 char *handler
, *nl
, *data
= NULL
;
749 guchar
*command
= NULL
;
751 handler
= handler_for(type
);
754 return NULL
; /* No current handler */
756 if (stat(handler
, &info
))
757 goto out
; /* Can't stat */
759 if ((!S_ISREG(info
.st_mode
)) || info
.st_size
> 256)
760 goto out
; /* Only use small regular files */
762 if (!load_file(handler
, &data
, &len
))
763 goto out
; /* Didn't load OK */
765 if (strncmp(data
, "#! /bin/sh\nexec ", 16) != 0)
766 goto out
; /* Not one of ours */
768 nl
= strchr(data
+ 16, '\n');
770 goto out
; /* No newline! */
772 command
= g_strndup(data
+ 16, nl
- data
- 16);
779 /* Find the current command which is used to run files of this type,
780 * and return a textual description of it.
781 * Only call for non-executable files.
782 * g_free() the result.
784 gchar
*describe_current_command(MIME_type
*type
)
790 g_return_val_if_fail(type
!= NULL
, NULL
);
792 handler
= handler_for(type
);
795 return g_strdup(_("No run action defined"));
797 if (mc_stat(handler
, &info
) !=0 )
799 desc
= g_strdup_printf(_("Error in handler %s: %s"), handler
,
804 if (S_ISDIR(info
.st_mode
))
807 uid_t dir_uid
= info
.st_uid
;
809 tmp
= make_path(handler
, "AppRun");
811 if (mc_lstat(tmp
, &info
) != 0 || info
.st_uid
!= dir_uid
812 || !(info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
813 desc
= g_strdup_printf(
814 _("Invalid application %s (bad AppRun)"),
816 /* Else, just report handler... */
821 /* It's not an application directory, and it's not a symlink... */
823 if (access(handler
, X_OK
) != 0)
825 desc
= g_strdup_printf(_("Non-executable %s"), handler
);
829 desc
= get_current_command(type
);
839 /* Display a dialog box allowing the user to set the default run action
842 void type_set_handler_dialog(MIME_type
*type
)
846 GtkWidget
*frame
, *entry
, *label
, *button
;
850 g_return_if_fail(type
!= NULL
);
852 dialog
= GTK_DIALOG(gtk_dialog_new());
853 gtk_dialog_set_has_separator(dialog
, FALSE
);
854 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
856 g_object_set_data(G_OBJECT(dialog
), "mime_type", type
);
858 gtk_window_set_title(GTK_WINDOW(dialog
), _("Set run action"));
860 radios
= radios_new(run_action_update
, dialog
);
861 g_object_set_data(G_OBJECT(dialog
), "rox-radios", radios
);
864 _("If a handler for the specific type isn't set up, "
865 "use this as the default."), SET_MEDIA
,
866 _("Set default for all `%s/<anything>'"),
870 _("Use this application for all files with this MIME "
872 _("Only for the type `%s' (%s/%s)"),
873 mime_type_comment(type
),
874 type
->media_type
, type
->subtype
);
876 radios_set_value(radios
, SET_TYPE
);
878 frame
= drop_box_new(_("Drop a suitable application here"));
880 g_object_set_data(G_OBJECT(dialog
), "rox-dropbox", frame
);
882 radios_pack(radios
, GTK_BOX(dialog
->vbox
));
883 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), frame
, TRUE
, TRUE
, 0);
885 g_signal_connect(frame
, "path_dropped",
886 G_CALLBACK(drag_app_dropped
), dialog
);
887 g_signal_connect(frame
, "clear",
888 G_CALLBACK(clear_run_action
), dialog
);
890 hbox
= gtk_hbox_new(FALSE
, 4);
891 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), hbox
, FALSE
, TRUE
, 4);
892 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
893 gtk_box_pack_start(GTK_BOX(hbox
), gtk_label_new(_("OR")),
895 gtk_box_pack_start(GTK_BOX(hbox
), gtk_hseparator_new(), TRUE
, TRUE
, 0);
897 hbox
= gtk_hbox_new(FALSE
, 4);
898 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), hbox
, FALSE
, TRUE
, 0);
900 label
= gtk_label_new(_("Enter a shell command:")),
901 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
902 gtk_box_pack_start(GTK_BOX(hbox
), label
, TRUE
, TRUE
, 4);
904 gtk_box_pack_start(GTK_BOX(hbox
),
905 new_help_button(show_shell_help
, NULL
), FALSE
, TRUE
, 0);
907 entry
= gtk_entry_new();
908 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), entry
, FALSE
, TRUE
, 0);
909 gtk_widget_grab_focus(entry
);
910 g_object_set_data(G_OBJECT(dialog
), "shell_command", entry
);
911 gtk_entry_set_activates_default(GTK_ENTRY(entry
), TRUE
);
913 /* If possible, fill in the entry box with the current command */
914 tmp
= get_current_command(type
);
917 gtk_entry_set_text(GTK_ENTRY(entry
), tmp
);
918 gtk_editable_set_position(GTK_EDITABLE(entry
), -1);
923 gtk_entry_set_text(GTK_ENTRY(entry
), " \"$@\"");
924 gtk_editable_set_position(GTK_EDITABLE(entry
), 0);
927 gtk_dialog_add_button(dialog
, GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
);
929 button
= button_new_mixed(GTK_STOCK_OK
, _("_Use Command"));
930 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
931 gtk_dialog_add_action_widget(dialog
, button
, GTK_RESPONSE_OK
);
933 hbox
= gtk_hbox_new(TRUE
, 4);
934 gtk_box_pack_start(GTK_BOX(dialog
->vbox
), hbox
, FALSE
, TRUE
, 0);
936 gtk_dialog_set_default_response(dialog
, GTK_RESPONSE_OK
);
938 g_signal_connect(dialog
, "response",
939 G_CALLBACK(set_action_response
), NULL
);
941 gtk_widget_show_all(GTK_WIDGET(dialog
));
944 /* path is an entry in Choices. If it's a symlink or a very small executable
945 * then just get rid of it, otherwise confirm first. It it doesn't exist,
948 * FALSE on error (abort operation).
950 static gboolean
remove_handler_with_confirm(const guchar
*path
)
954 if (lstat(path
, &info
) == 0)
956 /* A binding already exists... */
957 if (S_ISREG(info
.st_mode
) && info
.st_size
> 256)
959 if (!confirm(_("A run action already exists and is "
960 "quite a big program - are you sure "
961 "you want to delete it?"),
962 GTK_STOCK_DELETE
, NULL
))
970 report_error(_("Can't remove %s: %s"),
971 path
, g_strerror(errno
));
979 /* The user wants to set a new default action for files of this type (or just
980 * clear the action). Removes the current binding if possible and returns the
981 * path to save the new one to. NULL means cancel. g_free() the result.
983 static char *get_action_save_path(GtkWidget
*dialog
)
986 guchar
*type_name
= NULL
;
990 g_return_val_if_fail(dialog
!= NULL
, NULL
);
992 type
= g_object_get_data(G_OBJECT(dialog
), "mime_type");
993 radios
= g_object_get_data(G_OBJECT(dialog
), "rox-radios");
995 g_return_val_if_fail(radios
!= NULL
&& type
!= NULL
, NULL
);
997 if (radios_get_value(radios
) == SET_MEDIA
)
998 type_name
= g_strdup(type
->media_type
);
1000 type_name
= g_strconcat(type
->media_type
, "_",
1001 type
->subtype
, NULL
);
1003 path
= choices_find_xdg_path_save("", PROJECT
, SITE
, FALSE
);
1007 _("Choices saving is disabled by CHOICESPATH variable"));
1012 path
= choices_find_xdg_path_save(type_name
, "MIME-types", SITE
, TRUE
);
1014 if (!remove_handler_with_confirm(path
))
1021 MIME_type
*mime_type_from_base_type(int base_type
)
1027 case TYPE_DIRECTORY
:
1028 return inode_directory
;
1032 return inode_socket
;
1033 case TYPE_BLOCK_DEVICE
:
1034 return inode_block_dev
;
1035 case TYPE_CHAR_DEVICE
:
1036 return inode_char_dev
;
1040 return inode_unknown
;
1043 /* Takes the st_mode field from stat() and returns the base type.
1044 * Should not be a symlink.
1046 int mode_to_base_type(int st_mode
)
1048 if (S_ISREG(st_mode
))
1050 else if (S_ISDIR(st_mode
))
1051 return TYPE_DIRECTORY
;
1052 else if (S_ISBLK(st_mode
))
1053 return TYPE_BLOCK_DEVICE
;
1054 else if (S_ISCHR(st_mode
))
1055 return TYPE_CHAR_DEVICE
;
1056 else if (S_ISFIFO(st_mode
))
1058 else if (S_ISSOCK(st_mode
))
1060 else if (S_ISDOOR(st_mode
))
1066 /* Returns TRUE is this is something that is run by looking up its type
1067 * in MIME-types and, hence, can have its run action set.
1069 gboolean
can_set_run_action(DirItem
*item
)
1071 g_return_val_if_fail(item
!= NULL
, FALSE
);
1073 return item
->base_type
== TYPE_FILE
&& !EXECUTABLE_FILE(item
);
1076 /* Parse file type colours and allocate/free them as necessary */
1077 static void alloc_type_colours(void)
1079 gboolean success
[NUM_TYPE_COLOURS
];
1080 int change_count
= 0; /* No. needing realloc */
1082 static gboolean allocated
= FALSE
;
1085 for (i
= 0; i
< NUM_TYPE_COLOURS
; i
++)
1087 GdkColor
*c
= &type_colours
[i
];
1089 gushort g
= c
->green
;
1090 gushort b
= c
->blue
;
1092 gdk_color_parse(o_type_colours
[i
].value
, &type_colours
[i
]);
1094 if (allocated
&& (c
->red
!= r
|| c
->green
!= g
|| c
->blue
!= b
))
1098 /* Free colours if they were previously allocated and
1099 * have changed or become unneeded.
1101 if (allocated
&& (change_count
|| !o_display_colour_types
.int_value
))
1103 gdk_colormap_free_colors(gdk_rgb_get_colormap(),
1104 type_colours
, NUM_TYPE_COLOURS
);
1108 /* Allocate colours, unless they are still allocated (=> they didn't
1109 * change) or we don't want them anymore.
1110 * XXX: what should be done if allocation fails?
1112 if (!allocated
&& o_display_colour_types
.int_value
)
1114 gdk_colormap_alloc_colors(gdk_rgb_get_colormap(),
1115 type_colours
, NUM_TYPE_COLOURS
,
1116 FALSE
, TRUE
, success
);
1121 static void expire_timer(gpointer key
, gpointer value
, gpointer data
)
1123 MIME_type
*type
= value
;
1125 type
->image_time
= 0;
1128 static void options_changed(void)
1130 alloc_type_colours();
1131 if (o_icon_theme
.has_changed
)
1134 g_hash_table_foreach(type_hash
, expire_timer
, NULL
);
1139 /* Return a pointer to a (static) colour for this item. If colouring is
1140 * off, returns normal.
1142 GdkColor
*type_get_colour(DirItem
*item
, GdkColor
*normal
)
1144 int type
= item
->base_type
;
1146 if (!o_display_colour_types
.int_value
)
1149 if (EXECUTABLE_FILE(item
))
1151 else if (item
->flags
& ITEM_FLAG_APPDIR
)
1154 g_return_val_if_fail(type
>= 0 && type
< NUM_TYPE_COLOURS
, normal
);
1156 return &type_colours
[type
];
1159 static char **get_xdg_data_dirs(int *n_dirs
)
1165 env
= getenv("XDG_DATA_DIRS");
1167 env
= "/usr/local/share/:/usr/share/";
1168 dirs
= g_strsplit(env
, ":", 0);
1169 g_return_val_if_fail(dirs
!= NULL
, NULL
);
1170 for (n
= 0; dirs
[n
]; n
++)
1172 for (i
= n
; i
> 0; i
--)
1173 dirs
[i
] = dirs
[i
- 1];
1174 env
= getenv("XDG_DATA_HOME");
1176 dirs
[0] = g_strdup(env
);
1178 dirs
[0] = g_build_filename(g_get_home_dir(), ".local",
1184 /* Try to fill in 'type->comment' from this document */
1185 static void get_comment(MIME_type
*type
, const guchar
*path
)
1190 doc
= xml_cache_load(path
);
1194 node
= xml_get_section(doc
, TYPE_NS
, "comment");
1199 g_return_if_fail(type
->comment
== NULL
);
1200 val
= xmlNodeListGetString(node
->doc
, node
->xmlChildrenNode
, 1);
1201 type
->comment
= g_strdup(val
);
1205 g_object_unref(doc
);
1208 /* Fill in the comment field for this MIME type */
1209 static void find_comment(MIME_type
*type
)
1216 g_free(type
->comment
);
1217 type
->comment
= NULL
;
1220 dirs
= get_xdg_data_dirs(&n_dirs
);
1221 g_return_if_fail(dirs
!= NULL
);
1223 for (i
= 0; i
< n_dirs
; i
++)
1227 path
= g_strdup_printf("%s/mime/%s/%s.xml", dirs
[i
],
1228 type
->media_type
, type
->subtype
);
1229 get_comment(type
, path
);
1236 type
->comment
= g_strdup_printf("%s/%s", type
->media_type
,
1239 for (i
= 0; i
< n_dirs
; i
++)
1244 const char *mime_type_comment(MIME_type
*type
)
1249 return type
->comment
;
1252 static void unref_icon_theme(void)
1254 if (icon_theme
&& icon_theme
!= rox_theme
&& icon_theme
!= gnome_theme
)
1255 g_object_unref(icon_theme
);
1258 static void set_icon_theme(void)
1262 const char *theme_dir
;
1263 const char *theme_name
= o_icon_theme
.value
;
1265 if (!theme_name
|| !*theme_name
)
1268 if (!strcmp(theme_name
, "ROX"))
1272 icon_theme
= rox_theme
;
1274 else if (!strcmp(theme_name
, "gnome"))
1278 icon_theme
= gnome_theme
;
1282 if (icon_theme
== rox_theme
|| icon_theme
== gnome_theme
)
1283 icon_theme
= gtk_icon_theme_new();
1284 gtk_icon_theme_set_custom_theme(icon_theme
, theme_name
);
1287 /* Ensure the ROX theme exists. */
1289 icon_home
= g_build_filename(home_dir
, ".icons", "ROX", NULL
);
1290 if (stat(icon_home
, &info
) == 0)
1291 return; /* Already exists */
1293 /* First, create the .icons directory */
1294 theme_dir
= make_path(home_dir
, ".icons");
1295 if (!file_exists(theme_dir
))
1296 mkdir(theme_dir
, 0755);
1298 if (lstat(icon_home
, &info
) == 0)
1300 /* Probably a broken symlink, then. Remove it. */
1301 if (unlink(icon_home
))
1302 g_warning("Error removing broken symlink %s: %s", icon_home
, g_strerror(errno
));
1304 g_warning("Removed broken symlink %s", icon_home
);
1307 if (symlink(make_path(app_dir
, "ROX"), icon_home
))
1309 delayed_error(_("Failed to create symlink '%s':\n%s"), icon_home
, g_strerror(errno
));
1310 open_to_show(icon_home
);
1314 gtk_icon_theme_rescan_if_needed(icon_theme
);
1317 static guchar
*read_theme(Option
*option
)
1319 GtkOptionMenu
*om
= GTK_OPTION_MENU(option
->widget
);
1322 item
= GTK_LABEL(GTK_BIN(om
)->child
);
1324 g_return_val_if_fail(item
!= NULL
, g_strdup("ROX"));
1326 return g_strdup(gtk_label_get_text(item
));
1329 static void update_theme(Option
*option
)
1331 GtkOptionMenu
*om
= GTK_OPTION_MENU(option
->widget
);
1336 menu
= gtk_option_menu_get_menu(om
);
1338 kids
= gtk_container_get_children(GTK_CONTAINER(menu
));
1339 for (next
= kids
; next
; next
= next
->next
, i
++)
1341 GtkLabel
*item
= GTK_LABEL(GTK_BIN(next
->data
)->child
);
1344 /* The label actually moves from the menu!! */
1346 item
= GTK_LABEL(GTK_BIN(om
)->child
);
1348 label
= gtk_label_get_text(item
);
1350 g_return_if_fail(label
!= NULL
);
1352 if (strcmp(label
, option
->value
) == 0)
1358 gtk_option_menu_set_history(om
, i
);
1360 g_warning("Theme '%s' not found", option
->value
);
1363 static void add_themes_from_dir(GPtrArray
*names
, const char *dir
)
1368 if (access(dir
, F_OK
) != 0)
1371 list
= list_dir(dir
);
1372 g_return_if_fail(list
!= NULL
);
1374 for (i
= 0; i
< list
->len
; i
++)
1378 index_path
= g_build_filename(dir
, list
->pdata
[i
],
1379 "index.theme", NULL
);
1381 if (access(index_path
, F_OK
) == 0)
1382 g_ptr_array_add(names
, list
->pdata
[i
]);
1384 g_free(list
->pdata
[i
]);
1389 g_ptr_array_free(list
, TRUE
);
1392 static GList
*build_icon_theme(Option
*option
, xmlNode
*node
, guchar
*label
)
1394 GtkWidget
*button
, *menu
, *hbox
;
1396 gchar
**theme_dirs
= NULL
;
1400 g_return_val_if_fail(option
!= NULL
, NULL
);
1401 g_return_val_if_fail(label
!= NULL
, NULL
);
1403 hbox
= gtk_hbox_new(FALSE
, 4);
1405 gtk_box_pack_start(GTK_BOX(hbox
), gtk_label_new(_(label
)),
1408 button
= gtk_option_menu_new();
1409 gtk_box_pack_start(GTK_BOX(hbox
), button
, TRUE
, TRUE
, 0);
1411 menu
= gtk_menu_new();
1412 gtk_option_menu_set_menu(GTK_OPTION_MENU(button
), menu
);
1414 gtk_icon_theme_get_search_path(icon_theme
, &theme_dirs
, &n_dirs
);
1415 names
= g_ptr_array_new();
1416 for (i
= 0; i
< n_dirs
; i
++)
1417 add_themes_from_dir(names
, theme_dirs
[i
]);
1418 g_strfreev(theme_dirs
);
1420 g_ptr_array_sort(names
, strcmp2
);
1422 for (i
= 0; i
< names
->len
; i
++)
1425 char *name
= names
->pdata
[i
];
1427 item
= gtk_menu_item_new_with_label(name
);
1428 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1429 gtk_widget_show_all(item
);
1434 g_ptr_array_free(names
, TRUE
);
1436 option
->update_widget
= update_theme
;
1437 option
->read_widget
= read_theme
;
1438 option
->widget
= button
;
1440 gtk_signal_connect_object(GTK_OBJECT(button
), "changed",
1441 GTK_SIGNAL_FUNC(option_check_widget
),
1442 (GtkObject
*) option
);
1444 return g_list_append(NULL
, hbox
);
1447 GtkIconInfo
*theme_lookup_icon(const gchar
*icon_name
, gint size
,
1448 GtkIconLookupFlags flags
)
1450 GtkIconInfo
*result
= gtk_icon_theme_lookup_icon(icon_theme
,
1451 icon_name
, size
, flags
);
1453 if (!result
&& icon_theme
!= rox_theme
)
1456 result
= gtk_icon_theme_lookup_icon(rox_theme
,
1457 icon_name
, size
, flags
);
1459 if (!result
&& icon_theme
!= gnome_theme
)
1462 result
= gtk_icon_theme_lookup_icon(gnome_theme
,
1463 icon_name
, size
, flags
);
1468 GdkPixbuf
*theme_load_icon(const gchar
*icon_name
, gint size
,
1469 GtkIconLookupFlags flags
, GError
**perror
)
1471 GdkPixbuf
*result
= gtk_icon_theme_load_icon(icon_theme
,
1472 icon_name
, size
, flags
, NULL
);
1474 if (!result
&& icon_theme
!= gnome_theme
)
1477 result
= gtk_icon_theme_load_icon(gnome_theme
,
1478 icon_name
, size
, flags
, NULL
);
1480 if (!result
&& icon_theme
!= rox_theme
)
1483 result
= gtk_icon_theme_load_icon(rox_theme
,
1484 icon_name
, size
, flags
, perror
);