r126: Added better ref counting for file icons.
[rox-filer.git] / ROX-Filer / src / type.c
blobbb3c156fee1358a16ca6166b4cc148c6458ca6a8
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, 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 <glib.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <time.h>
32 #include "string.h"
33 #include "filer.h"
34 #include "pixmaps.h"
35 #include "apps.h"
36 #include "gui_support.h"
37 #include "choices.h"
38 #include "type.h"
39 #include "support.h"
40 #include "options.h"
42 /* Static prototypes */
43 static char *import_extensions(char *line);
45 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *) */
46 static GHashTable *extension_hash = NULL;
47 static char *current_type = NULL; /* (used while reading file) */
49 /* Most things on Unix are text files, so this is the default type */
50 MIME_type text_plain = {"text", "plain", NULL};
52 void type_init()
54 ChoicesList *paths, *next;
56 extension_hash = g_hash_table_new(g_str_hash, g_str_equal);
58 paths = choices_find_load_all("guess", "MIME-types");
59 while (paths)
61 current_type = NULL;
62 parse_file(paths->path, import_extensions);
63 next = paths->next;
64 g_free(paths->path);
65 g_free(paths);
66 paths = next;
70 /* Add one entry to the extension_hash table */
71 static void add_ext(char *type_name, char *ext)
73 MIME_type *new;
74 char *slash;
75 int len;
77 slash = strchr(type_name, '/');
78 g_return_if_fail(slash != NULL); /* XXX: Report nicely */
79 len = slash - type_name;
81 new = g_new(MIME_type, 1);
82 new->media_type = g_malloc(sizeof(char) * (len + 1));
83 memcpy(new->media_type, type_name, len);
84 new->media_type[len] = '\0';
86 new->subtype = g_strdup(slash + 1);
87 new->image = NULL;
89 g_hash_table_insert(extension_hash, g_strdup(ext), new);
92 /* Parse one line from the file and add entries to extension_hash */
93 static char *import_extensions(char *line)
96 if (*line == '\0' || *line == '#')
97 return NULL; /* Comment */
99 if (isspace(*line))
101 if (!current_type)
102 return "Missing MIME-type";
103 while (*line && isspace(*line))
104 line++;
106 if (strncmp(line, "ext:", 4) == 0)
108 char *ext;
109 line += 4;
111 for (;;)
113 while (*line && isspace(*line))
114 line++;
115 if (*line == '\0')
116 break;
117 ext = line;
118 while (*line && !isspace(*line))
119 line++;
120 if (*line)
121 *line++ = '\0';
122 add_ext(current_type, ext);
125 /* else ignore */
127 else
129 char *type = line;
130 while (*line && !isspace(*line))
131 line++;
132 if (*line)
133 *line++ = '\0';
134 while (*line && isspace(*line))
135 line++;
136 if (*line)
137 return "Trailing chars after MIME-type";
138 current_type = g_strdup(type);
140 return NULL;
143 char *basetype_name(FileItem *item)
145 if (item->flags & ITEM_FLAG_SYMLINK)
146 return "Sym link";
147 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
148 return "Mount point";
149 else if (item->flags & ITEM_FLAG_APPDIR)
150 return "App dir";
152 switch (item->base_type)
154 case TYPE_FILE:
155 return "File";
156 case TYPE_DIRECTORY:
157 return "Dir";
158 case TYPE_CHAR_DEVICE:
159 return "Char dev";
160 case TYPE_BLOCK_DEVICE:
161 return "Block dev";
162 case TYPE_PIPE:
163 return "Pipe";
164 case TYPE_SOCKET:
165 return "Socket";
168 return "Unknown";
171 /* MIME-type guessing */
173 /* Returns a pointer to the MIME-type string, or NULL if we have
174 * no opinion.
176 MIME_type *type_from_path(char *path)
178 char *dot;
180 dot = strrchr(path, '.');
181 if (dot)
183 MIME_type *type;
184 type = g_hash_table_lookup(extension_hash, dot + 1);
185 if (type)
186 return type;
189 return &text_plain;
192 /* Actions for types */
194 gboolean type_open(char *path, MIME_type *type)
196 char *argv[] = {NULL, NULL, NULL};
197 char *open;
198 char *type_name;
199 gboolean retval = TRUE;
200 struct stat info;
202 argv[1] = path;
204 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
205 open = choices_find_path_load_shared(type_name, "MIME-types");
206 g_free(type_name);
207 if (!open)
209 open = choices_find_path_load_shared(type->media_type,
210 "MIME-types");
211 if (!open)
212 return FALSE;
215 if (stat(open, &info))
217 report_error("ROX-Filer", g_strerror(errno));
218 return FALSE;
221 if (S_ISDIR(info.st_mode))
222 argv[0] = g_strconcat(open, "/AppRun", NULL);
223 else
224 argv[0] = open;
226 if (!spawn_full(argv, getenv("HOME"), 0))
228 report_error("ROX-Filer",
229 "Failed to fork() child process");
230 retval = FALSE;
233 if (argv[0] != open)
234 g_free(argv[0]);
236 return retval;
239 /* Return the image for this type, loading it if needed.
240 * Places to check are: (eg type="text_plain", base="text")
241 * 1. Choices:MIME-icons/<type>
242 * 2. Choices:MIME-icons/<base>
243 * 3. Unknown type icon.
245 * Note: You must pixmap_unref() the image afterwards.
247 MaskedPixmap *type_to_icon(GtkWidget *window, MIME_type *type)
249 char *path;
250 char *type_name;
251 time_t now;
253 g_return_val_if_fail(type != NULL, default_pixmap + TYPE_UNKNOWN);
255 now = time(NULL);
256 /* Already got an image? */
257 if (type->image)
259 /* Yes - don't recheck too often */
260 if (abs(now - type->image_time) < 2)
262 pixmap_ref(type->image);
263 return type->image;
265 pixmap_unref(type->image);
266 type->image = NULL;
269 type_name = g_strconcat(type->media_type, "_",
270 type->subtype, ".xpm", NULL);
271 path = choices_find_path_load_shared(type_name, "MIME-icons");
272 if (!path)
274 strcpy(type_name + strlen(type->media_type), ".xpm");
275 path = choices_find_path_load_shared(type_name, "MIME-icons");
278 g_free(type_name);
280 if (path)
281 type->image = load_pixmap_from(window, path);
283 if (!type->image)
285 type->image = default_pixmap + TYPE_UNKNOWN;
286 pixmap_ref(type->image);
289 type->image_time = now;
291 pixmap_ref(type->image);
292 return type->image;
295 GdkAtom type_to_atom(MIME_type *type)
297 char *str;
298 GdkAtom retval;
300 g_return_val_if_fail(type != NULL, GDK_NONE);
302 str = g_strconcat(type->media_type, "/", type->subtype, NULL);
303 retval = gdk_atom_intern(str, FALSE);
304 g_free(str);
306 return retval;