r79: Added choices_find_load_all() - now ALL 'guess' files are loaded and merged,
[rox-filer.git] / ROX-Filer / src / type.c
blob333f69117579691c140b47fab917d9678430c06e
1 /* vi: set cindent:
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
6 */
8 /* type.c - code for dealing with filetypes */
10 #include <glib.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <ctype.h>
17 #include "string.h"
18 #include "filer.h"
19 #include "pixmaps.h"
20 #include "apps.h"
21 #include "gui_support.h"
22 #include "choices.h"
23 #include "type.h"
24 #include "support.h"
25 #include "options.h"
27 /* Static prototypes */
28 static char *import_extensions(char *line);
30 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *) */
31 static GHashTable *extension_hash = NULL;
32 static char *current_type = NULL; /* (used while reading file) */
34 /* Most things on Unix are text files, so this is the default type */
35 static MIME_type text_plain = {"text", "plain"};
37 void type_init()
39 ChoicesList *paths, *next;
41 extension_hash = g_hash_table_new(g_str_hash, g_str_equal);
43 paths = choices_find_load_all("guess", "MIME-types");
44 while (paths)
46 current_type = NULL;
47 parse_file(paths->path, import_extensions);
48 next = paths->next;
49 g_free(paths->path);
50 g_free(paths);
51 paths = next;
55 /* Add one entry to the extension_hash table */
56 static void add_ext(char *type_name, char *ext)
58 MIME_type *new;
59 char *slash;
60 int len;
62 slash = strchr(type_name, '/');
63 g_return_if_fail(slash != NULL); /* XXX: Report nicely */
64 len = slash - type_name;
66 new = g_malloc(sizeof(MIME_type));
67 new->media_type = g_malloc(sizeof(char) * (len + 1));
68 memcpy(new->media_type, type_name, len);
69 new->media_type[len] = '\0';
71 new->subtype = g_strdup(slash + 1);
72 new->image = NULL;
74 g_hash_table_insert(extension_hash, g_strdup(ext), new);
77 /* Parse one line from the file and add entries to extension_hash */
78 static char *import_extensions(char *line)
81 if (*line == '\0' || *line == '#')
82 return NULL; /* Comment */
84 if (isspace(*line))
86 if (!current_type)
87 return "Missing MIME-type";
88 while (*line && isspace(*line))
89 line++;
91 if (strncmp(line, "ext:", 4) == 0)
93 char *ext;
94 line += 4;
96 for (;;)
98 while (*line && isspace(*line))
99 line++;
100 if (*line == '\0')
101 break;
102 ext = line;
103 while (*line && !isspace(*line))
104 line++;
105 if (*line)
106 *line++ = '\0';
107 add_ext(current_type, ext);
110 /* else ignore */
112 else
114 char *type = line;
115 while (*line && !isspace(*line))
116 line++;
117 if (*line)
118 *line++ = '\0';
119 while (*line && isspace(*line))
120 line++;
121 if (*line)
122 return "Trailing chars after MIME-type";
123 current_type = g_strdup(type);
125 return NULL;
128 char *basetype_name(FileItem *item)
130 if (item->flags & ITEM_FLAG_SYMLINK)
131 return "Sym link";
132 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
133 return "Mount point";
134 else if (item->flags & ITEM_FLAG_APPDIR)
135 return "App dir";
137 switch (item->base_type)
139 case TYPE_FILE:
140 return "File";
141 case TYPE_DIRECTORY:
142 return "Dir";
143 case TYPE_CHAR_DEVICE:
144 return "Char dev";
145 case TYPE_BLOCK_DEVICE:
146 return "Block dev";
147 case TYPE_PIPE:
148 return "Pipe";
149 case TYPE_SOCKET:
150 return "Socket";
153 return "Unknown";
156 /* MIME-type guessing */
158 /* Returns a pointer to the MIME-type string, or NULL if we have
159 * no opinion.
161 MIME_type *type_from_path(char *path)
163 char *dot;
165 dot = strrchr(path, '.');
166 if (dot)
168 MIME_type *type;
169 type = g_hash_table_lookup(extension_hash, dot + 1);
170 if (type)
171 return type;
174 return &text_plain;
177 /* Actions for types */
179 gboolean type_open(char *path, MIME_type *type)
181 char *argv[] = {NULL, path, NULL};
182 char *open;
183 char *type_name;
185 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
186 open = choices_find_path_load_shared(type_name, "MIME-types");
187 g_free(type_name);
188 if (!open)
190 open = choices_find_path_load_shared(type->media_type,
191 "MIME-types");
192 if (!open)
193 return FALSE;
196 argv[0] = g_strconcat(open, "/AppRun", NULL);
198 if (!spawn_full(argv, getenv("HOME"), 0))
199 report_error("ROX-Filer",
200 "Failed to fork() child process");
202 g_free(argv[0]);
204 return TRUE;
207 /* Tries to load image from <handler>/MIME-icons/<icon>.xpm */
208 static MaskedPixmap *try_icon_path(GtkWidget *window, char *handler, char *icon)
210 char *path;
211 MaskedPixmap *image;
213 if (!handler)
214 return NULL;
216 path = g_strconcat(handler, "/MIME-icons/", icon, ".xpm", NULL);
217 image = load_pixmap_from(window, path);
218 g_free(path);
220 return image;
223 /* Return the image for this type, loading it if needed.
224 * Find handler application, <app>, then:
225 * Places to check are: (eg type="text_plain", base="text")
226 * 1. <app>/MIME-icons/<type>
227 * 2. <app>/MIME-icons/<base>
228 * 3. $APP_DIR/MIME-icons/<base>
229 * 4. Unknown type icon.
231 MaskedPixmap *type_to_icon(GtkWidget *window, MIME_type *type)
233 char *open;
234 char *type_name;
235 MaskedPixmap *i;
237 g_return_val_if_fail(type != NULL, default_pixmap + TYPE_UNKNOWN);
239 /* Already got an image? TODO: Is it out-of-date? */
240 if (type->image)
241 return type->image;
243 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
245 open = choices_find_path_load_shared(type_name, "MIME-types");
246 if (!open)
247 open = choices_find_path_load_shared(type->media_type,
248 "MIME-types");
249 if (((i = try_icon_path(window, open, type_name)))
250 || ((i = try_icon_path(window, open, type->media_type)))
251 || ((i = try_icon_path(window, getenv("APP_DIR"), type->media_type))))
252 type->image = i;
253 else
254 type->image = default_pixmap + TYPE_UNKNOWN;
256 g_free(type_name);
258 return i;
261 GdkAtom type_to_atom(MIME_type *type)
263 char *str;
264 GdkAtom retval;
266 g_return_val_if_fail(type != NULL, GDK_NONE);
268 str = g_strconcat(type->media_type, "/", type->subtype, NULL);
269 retval = gdk_atom_intern(str, FALSE);
270 g_free(str);
272 return retval;