r277: Started adding support for setting run actions. Dialog box displays
[rox-filer/ma.git] / ROX-Filer / src / type.c
bloba3ddfa08b69d01edbb563f0fac39a1f2ed2793e7
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
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)
10 * any later version.
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
15 * more details.
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 */
24 #include "config.h"
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <time.h>
32 #include <sys/param.h>
34 #include <glib.h>
36 #include "string.h"
37 #include "main.h"
38 #include "filer.h"
39 #include "pixmaps.h"
40 #include "run.h"
41 #include "gui_support.h"
42 #include "choices.h"
43 #include "type.h"
44 #include "support.h"
45 #include "options.h"
47 /* Static prototypes */
48 static char *import_extensions(guchar *line);
49 static void import_for_dir(guchar *path);
51 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *) */
52 static GHashTable *extension_hash = NULL;
53 static char *current_type = NULL; /* (used while reading file) */
55 /* Most things on Unix are text files, so this is the default type */
56 MIME_type text_plain = {"text", "plain", NULL};
58 void type_init()
60 int i;
61 GPtrArray *list;
63 extension_hash = g_hash_table_new(g_str_hash, g_str_equal);
65 current_type = NULL;
66 parse_file(make_path(getenv("APP_DIR"), "MIME-info")->str,
67 import_extensions);
69 list = choices_list_dirs("MIME-info");
70 for (i = 0; i < list->len; i++)
71 import_for_dir((gchar *) g_ptr_array_index(list, i));
72 choices_free_list(list);
75 /* Parse every file in 'dir' */
76 static void import_for_dir(guchar *path)
78 DIR *dir;
79 struct dirent *item;
81 dir = opendir(path);
82 if (!dir)
83 return;
85 while ((item = readdir(dir)))
87 if (item->d_name[0] == '.')
88 continue;
90 current_type = NULL;
91 parse_file(make_path(path, item->d_name)->str,
92 import_extensions);
95 closedir(dir);
98 /* Add one entry to the extension_hash table */
99 static void add_ext(char *type_name, char *ext)
101 MIME_type *new;
102 char *slash;
103 int len;
105 slash = strchr(type_name, '/');
106 g_return_if_fail(slash != NULL); /* XXX: Report nicely */
107 len = slash - type_name;
109 new = g_new(MIME_type, 1);
110 new->media_type = g_malloc(sizeof(char) * (len + 1));
111 memcpy(new->media_type, type_name, len);
112 new->media_type[len] = '\0';
114 new->subtype = g_strdup(slash + 1);
115 new->image = NULL;
117 g_hash_table_insert(extension_hash, g_strdup(ext), new);
120 /* Parse one line from the file and add entries to extension_hash */
121 static char *import_extensions(guchar *line)
124 if (*line == '\0' || *line == '#')
125 return NULL; /* Comment */
127 if (isspace(*line))
129 if (!current_type)
130 return _("Missing MIME-type");
131 while (*line && isspace(*line))
132 line++;
134 if (strncmp(line, "ext:", 4) == 0)
136 char *ext;
137 line += 4;
139 for (;;)
141 while (*line && isspace(*line))
142 line++;
143 if (*line == '\0')
144 break;
145 ext = line;
146 while (*line && !isspace(*line))
147 line++;
148 if (*line)
149 *line++ = '\0';
150 add_ext(current_type, ext);
153 /* else ignore */
155 else
157 char *type = line;
158 while (*line && *line != ':' && !isspace(*line))
159 line++;
160 if (*line)
161 *line++ = '\0';
162 while (*line && isspace(*line))
163 line++;
164 if (*line)
165 return _("Trailing chars after MIME-type");
166 current_type = g_strdup(type);
168 return NULL;
171 char *basetype_name(DirItem *item)
173 if (item->flags & ITEM_FLAG_SYMLINK)
174 return _("Sym link");
175 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
176 return _("Mount point");
177 else if (item->flags & ITEM_FLAG_APPDIR)
178 return _("App dir");
180 switch (item->base_type)
182 case TYPE_FILE:
183 return _("File");
184 case TYPE_DIRECTORY:
185 return _("Dir");
186 case TYPE_CHAR_DEVICE:
187 return _("Char dev");
188 case TYPE_BLOCK_DEVICE:
189 return _("Block dev");
190 case TYPE_PIPE:
191 return _("Pipe");
192 case TYPE_SOCKET:
193 return _("Socket");
196 return _("Unknown");
199 /* MIME-type guessing */
201 /* Returns a pointer to the MIME-type string, or NULL if we have
202 * no opinion.
204 MIME_type *type_from_path(char *path)
206 char *dot;
208 dot = strrchr(path, '.');
209 if (dot)
211 MIME_type *type;
212 type = g_hash_table_lookup(extension_hash, dot + 1);
213 if (type)
214 return type;
217 return &text_plain;
220 /* Actions for types */
222 gboolean type_open(char *path, MIME_type *type)
224 char *argv[] = {NULL, NULL, NULL};
225 char *open;
226 char *type_name;
227 gboolean retval = TRUE;
228 struct stat info;
230 argv[1] = path;
232 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
233 open = choices_find_path_load(type_name, "MIME-types");
234 g_free(type_name);
235 if (!open)
237 open = choices_find_path_load(type->media_type,
238 "MIME-types");
239 if (!open)
240 return FALSE;
243 if (stat(open, &info))
245 report_error(PROJECT, g_strerror(errno));
246 return FALSE;
249 if (S_ISDIR(info.st_mode))
250 argv[0] = g_strconcat(open, "/AppRun", NULL);
251 else
252 argv[0] = open;
254 if (!spawn_full(argv, home_dir))
256 report_error(PROJECT,
257 _("Failed to fork() child process"));
258 retval = FALSE;
261 if (argv[0] != open)
262 g_free(argv[0]);
264 return retval;
267 /* Return the image for this type, loading it if needed.
268 * Places to check are: (eg type="text_plain", base="text")
269 * 1. Choices:MIME-icons/<type>
270 * 2. Choices:MIME-icons/<base>
271 * 3. Unknown type icon.
273 * Note: You must pixmap_unref() the image afterwards.
275 MaskedPixmap *type_to_icon(MIME_type *type)
277 char *path;
278 char *type_name;
279 time_t now;
281 g_return_val_if_fail(type != NULL, default_pixmap[TYPE_UNKNOWN]);
283 now = time(NULL);
284 /* Already got an image? */
285 if (type->image)
287 /* Yes - don't recheck too often */
288 if (abs(now - type->image_time) < 2)
290 pixmap_ref(type->image);
291 return type->image;
293 pixmap_unref(type->image);
294 type->image = NULL;
297 type_name = g_strconcat(type->media_type, "_",
298 type->subtype, ".xpm", NULL);
299 path = choices_find_path_load(type_name, "MIME-icons");
300 if (!path)
302 strcpy(type_name + strlen(type->media_type), ".xpm");
303 path = choices_find_path_load(type_name, "MIME-icons");
306 g_free(type_name);
308 if (path)
309 type->image = g_fscache_lookup(pixmap_cache, path);
311 if (!type->image)
313 type->image = default_pixmap[TYPE_UNKNOWN];
314 pixmap_ref(type->image);
317 type->image_time = now;
319 pixmap_ref(type->image);
320 return type->image;
323 GdkAtom type_to_atom(MIME_type *type)
325 char *str;
326 GdkAtom retval;
328 g_return_val_if_fail(type != NULL, GDK_NONE);
330 str = g_strconcat(type->media_type, "/", type->subtype, NULL);
331 retval = gdk_atom_intern(str, FALSE);
332 g_free(str);
334 return retval;
337 /* Display a box allowing the user to set the run action for this type */
338 void show_set_run_action(MIME_type *type)
340 static GtkWidget *box = NULL;
341 static GtkWidget *pixmap = NULL, *link_path, *explain_label;
342 guchar *type_name, *path;
343 struct stat info;
344 static MaskedPixmap *drop = NULL;
345 MaskedPixmap *pic;
346 guchar *tmp;
348 if (!box)
350 GtkWidget *vbox, *event, *hbox, *button, *frame;
351 GtkWidget *link_box;
352 GtkTargetEntry targets[] = {
353 {"text/uri-list", 0, 0},
356 box = gtk_window_new(GTK_WINDOW_DIALOG);
357 gtk_container_set_border_width(GTK_CONTAINER(box), 4);
359 vbox = gtk_vbox_new(FALSE, 0);
360 gtk_container_add(GTK_CONTAINER(box), vbox);
362 explain_label = gtk_label_new("");
363 gtk_box_pack_start(GTK_BOX(vbox), explain_label,
364 FALSE, TRUE, 4);
366 frame = gtk_frame_new(NULL);
367 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
368 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
369 event = gtk_event_box_new();
370 gtk_container_add(GTK_CONTAINER(frame), event);
371 gtk_drag_dest_set(event, GTK_DEST_DEFAULT_ALL, targets,
372 sizeof(targets) / sizeof(*targets),
373 GDK_ACTION_COPY | GDK_ACTION_PRIVATE);
375 tmp = g_strconcat(getenv("APP_DIR"), "/pixmaps/drop.xpm", NULL);
376 drop = g_fscache_lookup(pixmap_cache, tmp);
377 g_free(tmp);
379 link_box = gtk_vbox_new(FALSE, 4);
380 gtk_container_add(GTK_CONTAINER(event), link_box);
382 pixmap = gtk_pixmap_new(drop->pixmap, drop->mask);
383 gtk_box_pack_start(GTK_BOX(link_box), pixmap, FALSE, TRUE, 4);
384 link_path = gtk_label_new("<path>");
385 gtk_misc_set_padding(GTK_MISC(link_path), 4, 0);
386 gtk_box_pack_start(GTK_BOX(link_box),
387 link_path, FALSE, TRUE, 4);
389 hbox = gtk_hbox_new(TRUE, 0);
390 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 4);
392 button = gtk_button_new_with_label(_("Save"));
393 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 4);
394 button = gtk_button_new_with_label(_("Cancel"));
395 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
396 GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(box));
397 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 4);
400 if (GTK_WIDGET_VISIBLE(box))
401 gtk_widget_hide(box);
403 type_name = g_strconcat(type->media_type, "/", type->subtype, NULL);
404 gtk_window_set_title(GTK_WINDOW(box), type_name);
405 tmp = g_strdup_printf(
406 _("Default run action for files of type '%s':"),
407 type_name);
408 gtk_label_set_text(GTK_LABEL(explain_label), tmp);
409 g_free(tmp);
410 g_free(type_name);
412 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
413 path = choices_find_path_load(type_name, "MIME-types");
414 if (!path)
415 path = choices_find_path_load(type->media_type, "MIME-types");
417 pic = NULL;
418 if (path && stat(path, &info) == 0)
420 if (S_ISDIR(info.st_mode))
422 tmp = g_strconcat(path, "/AppIcon.xpm", NULL);
423 pic = g_fscache_lookup(pixmap_cache, tmp);
424 g_free(tmp);
425 if (!pic)
427 pic = default_pixmap[TYPE_APPDIR];
428 pixmap_ref(pic);
431 else
433 pic = default_pixmap[TYPE_EXEC_FILE];
434 pixmap_ref(pic);
438 if (!pic)
440 pic = drop;
441 gtk_label_set_text(GTK_LABEL(link_path),
442 _("No run action set"));
444 else
446 char buffer[MAXPATHLEN + 1];
447 int got;
449 got = readlink(path, buffer, sizeof(buffer) - 1);
450 if (got > 0)
452 buffer[got] = '\0';
453 gtk_label_set_text(GTK_LABEL(link_path), buffer);
455 else
456 gtk_label_set_text(GTK_LABEL(link_path), path);
459 gtk_pixmap_set(GTK_PIXMAP(pixmap), pic->pixmap, pic->mask);
460 if (pic != drop)
461 g_fscache_data_unref(pixmap_cache, pic);
463 g_free(path);
465 gtk_widget_show_all(box);