r69: Tidied up the options system a bit. Added drag-and-drop section (with
[rox-filer.git] / ROX-Filer / src / type.c
blob16560ae8b3de483a3fa132c3efd7f7acfda1896f
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 char *path;
41 extension_hash = g_hash_table_new(g_str_hash, g_str_equal);
43 path = choices_find_path_load_shared("guess", "MIME-types");
44 if (path)
46 current_type = NULL;
47 parse_file(path, import_extensions);
51 /* Add one entry to the extension_hash table */
52 static void add_ext(char *type_name, char *ext)
54 MIME_type *new;
55 char *slash;
56 int len;
58 slash = strchr(type_name, '/');
59 g_return_if_fail(slash != NULL); /* XXX: Report nicely */
60 len = slash - type_name;
62 new = g_malloc(sizeof(MIME_type));
63 new->media_type = g_malloc(sizeof(char) * (len + 1));
64 memcpy(new->media_type, type_name, len);
65 new->media_type[len] = '\0';
67 new->subtype = g_strdup(slash + 1);
68 new->image = NULL;
70 g_hash_table_insert(extension_hash, g_strdup(ext), new);
73 /* Parse one line from the file and add entries to extension_hash */
74 static char *import_extensions(char *line)
77 if (*line == '\0' || *line == '#')
78 return NULL; /* Comment */
80 if (isspace(*line))
82 if (!current_type)
83 return "Missing MIME-type";
84 while (*line && isspace(*line))
85 line++;
87 if (strncmp(line, "ext:", 4) == 0)
89 char *ext;
90 line += 4;
92 for (;;)
94 while (*line && isspace(*line))
95 line++;
96 if (*line == '\0')
97 break;
98 ext = line;
99 while (*line && !isspace(*line))
100 line++;
101 if (*line)
102 *line++ = '\0';
103 add_ext(current_type, ext);
106 /* else ignore */
108 else
110 char *type = line;
111 while (*line && !isspace(*line))
112 line++;
113 if (*line)
114 *line++ = '\0';
115 while (*line && isspace(*line))
116 line++;
117 if (*line)
118 return "Trailing chars after MIME-type";
119 current_type = g_strdup(type);
121 return NULL;
124 char *basetype_name(FileItem *item)
126 if (item->flags & ITEM_FLAG_SYMLINK)
127 return "Sym link";
128 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
129 return "Mount point";
130 else if (item->flags & ITEM_FLAG_APPDIR)
131 return "App dir";
133 switch (item->base_type)
135 case TYPE_FILE:
136 return "File";
137 case TYPE_DIRECTORY:
138 return "Dir";
139 case TYPE_CHAR_DEVICE:
140 return "Char dev";
141 case TYPE_BLOCK_DEVICE:
142 return "Block dev";
143 case TYPE_PIPE:
144 return "Pipe";
145 case TYPE_SOCKET:
146 return "Socket";
149 return "Unknown";
152 /* MIME-type guessing */
154 /* Returns a pointer to the MIME-type string, or NULL if we have
155 * no opinion.
157 MIME_type *type_from_path(char *path)
159 char *dot;
161 dot = strrchr(path, '.');
162 if (dot)
164 MIME_type *type;
165 type = g_hash_table_lookup(extension_hash, dot + 1);
166 if (type)
167 return type;
170 return &text_plain;
173 /* Actions for types */
175 gboolean type_open(char *path, MIME_type *type)
177 char *argv[] = {NULL, path, NULL};
178 char *open;
179 char *type_name;
181 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
182 open = choices_find_path_load_shared(type_name, "MIME-types");
183 g_free(type_name);
184 if (!open)
186 open = choices_find_path_load_shared(type->media_type,
187 "MIME-types");
188 if (!open)
189 return FALSE;
192 argv[0] = g_strconcat(open, "/AppRun", NULL);
194 if (!spawn_full(argv, getenv("HOME"), 0))
195 report_error("ROX-Filer",
196 "Failed to fork() child process");
198 g_free(argv[0]);
200 return TRUE;
203 /* Tries to load image from <handler>/MIME-icons/<icon>.xpm */
204 static MaskedPixmap *try_icon_path(GtkWidget *window, char *handler, char *icon)
206 char *path;
207 MaskedPixmap *image;
209 if (!handler)
210 return NULL;
212 path = g_strconcat(handler, "/MIME-icons/", icon, ".xpm", NULL);
213 image = load_pixmap_from(window, path);
214 g_free(path);
216 return image;
219 /* Return the image for this type, loading it if needed.
220 * Find handler application, <app>, then:
221 * Places to check are: (eg type="text_plain", base="text")
222 * 1. <app>/MIME-icons/<type>
223 * 2. <app>/MIME-icons/<base>
224 * 3. $APP_DIR/MIME-icons/<base>
225 * 4. Unknown type icon.
227 MaskedPixmap *type_to_icon(GtkWidget *window, MIME_type *type)
229 char *open;
230 char *type_name;
231 MaskedPixmap *i;
233 g_return_val_if_fail(type != NULL, default_pixmap + TYPE_UNKNOWN);
235 /* Already got an image? TODO: Is it out-of-date? */
236 if (type->image)
237 return type->image;
239 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
241 open = choices_find_path_load_shared(type_name, "MIME-types");
242 if (!open)
243 open = choices_find_path_load_shared(type->media_type,
244 "MIME-types");
245 if (((i = try_icon_path(window, open, type_name)))
246 || ((i = try_icon_path(window, open, type->media_type)))
247 || ((i = try_icon_path(window, getenv("APP_DIR"), type->media_type))))
248 type->image = i;
249 else
250 type->image = default_pixmap + TYPE_UNKNOWN;
252 g_free(type_name);
254 return i;