]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-backends-manager.c
Fix memory leak.
[evince.git] / libdocument / ev-backends-manager.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21
22 #include <glib/gstdio.h>
23
24 #include "ev-module.h"
25 #include "ev-backends-manager.h"
26
27 static GList *ev_backends_list = NULL;
28
29 typedef struct _EvBackendInfo EvBackendInfo;
30 struct _EvBackendInfo {
31         gchar       *module_name;
32         GTypeModule *module;
33
34         GType        type_id;
35
36         gchar       *type_desc;
37         gchar      **mime_types;
38 };
39
40 #define EV_BACKENDS_GROUP     "Evince Backend"
41 #define EV_BACKENDS_EXTENSION ".evince-backend"
42
43 static void
44 ev_backend_info_free (EvBackendInfo *info)
45 {
46         g_free (info->module_name);
47         g_free (info->type_desc);
48         g_strfreev (info->mime_types);
49         g_free (info);
50 }
51
52 static EvBackendInfo *
53 ev_backends_manager_load_backend (const gchar *file)
54 {
55         EvBackendInfo *info;
56         GKeyFile      *backend_file = NULL;
57         GError        *error = NULL;
58
59         backend_file = g_key_file_new ();
60         if (!g_key_file_load_from_file (backend_file, file, G_KEY_FILE_NONE, &error)) {
61                 g_warning ("Error opening backend file %s: %s",
62                            file, error->message);
63                 g_error_free (error);
64                 g_key_file_free (backend_file);
65
66                 return NULL;
67         }
68
69         info = g_new0 (EvBackendInfo, 1);
70         info->module_name = g_key_file_get_string (backend_file, EV_BACKENDS_GROUP,
71                                                    "Module", NULL);
72         if (!info->module_name) {
73                 g_warning ("Bad evince backend file %s: Could not find 'Module'",
74                            file);
75                 ev_backend_info_free (info);
76                 g_key_file_free (backend_file);
77
78                 return NULL;
79         }
80
81         info->type_desc = g_key_file_get_locale_string (backend_file, EV_BACKENDS_GROUP,
82                                                         "TypeDescription", NULL, NULL);
83         if (!info->type_desc) {
84                 g_warning ("Bad evince backend file %s: Could not find 'TypeDescription'",
85                            file);
86                 ev_backend_info_free (info);
87                 g_key_file_free (backend_file);
88
89                 return NULL;
90         }
91
92         info->mime_types = g_key_file_get_string_list (backend_file, EV_BACKENDS_GROUP,
93                                                        "MimeType", NULL, NULL);
94         if (!info->mime_types) {
95                 g_warning ("Bad evince backend file %s: Could not find 'MimeType'",
96                            file);
97                 ev_backend_info_free (info);
98                 g_key_file_free (backend_file);
99
100                 return NULL;
101         }
102
103         g_key_file_free (backend_file);
104
105         return info;
106 }
107
108 static gboolean
109 ev_backends_manager_load (void)
110 {
111         GDir        *dir;
112         const gchar *dirent;
113         GError      *error = NULL;
114
115         dir = g_dir_open (EV_BACKENDSDIR, 0, &error);
116         if (!dir) {
117                 g_warning (error->message);
118                 g_error_free (error);
119
120                 return FALSE;
121         }
122
123         while ((dirent = g_dir_read_name (dir))) {
124                 EvBackendInfo *info;
125                 gchar         *file;
126                 
127                 if (!g_str_has_suffix (dirent, EV_BACKENDS_EXTENSION))
128                         continue;
129
130                 file = g_build_filename (EV_BACKENDSDIR, dirent, NULL);
131                 info = ev_backends_manager_load_backend (file);
132                 g_free (file);
133
134                 if (!info)
135                         continue;
136                 
137                 ev_backends_list = g_list_prepend (ev_backends_list, info);
138         }
139
140         g_dir_close (dir);
141
142         return TRUE;
143 }
144
145 gboolean
146 ev_backends_manager_init (void)
147 {
148         if (ev_backends_list)
149                 return FALSE;
150
151         return ev_backends_manager_load ();
152 }
153
154 void
155 ev_backends_manager_shutdown (void)
156 {
157         g_list_foreach (ev_backends_list, (GFunc)ev_backend_info_free, NULL);
158         g_list_free (ev_backends_list);
159         ev_backends_list = NULL;
160 }
161
162 static EvBackendInfo *
163 ev_backends_manager_get_backend_info (const gchar *mime_type)
164 {
165         GList *l;
166
167         for (l = ev_backends_list; l; l = g_list_next (l)) {
168                 EvBackendInfo *info;
169                 gint           i = 0;
170                 const char    *mime;
171                 
172                 info = (EvBackendInfo *)l->data;
173                 
174                 while ((mime = info->mime_types[i++])) {
175                         if (g_ascii_strcasecmp (mime, mime_type) == 0)
176                                 return info;
177                 }
178         }
179
180         return NULL;
181 }
182
183 EvDocument *
184 ev_backends_manager_get_document (const gchar *mime_type)
185 {
186         EvDocument    *document;
187         EvBackendInfo *info;
188
189         info = ev_backends_manager_get_backend_info (mime_type);
190         if (!info)
191                 return NULL;
192
193         if (!info->module) {
194                 gchar *path;
195                 
196                 path = g_module_build_path (EV_BACKENDSDIR, info->module_name);
197                 info->module = G_TYPE_MODULE (ev_module_new (path));
198                 g_free (path);
199         }
200         
201         if (!g_type_module_use (info->module)) {
202                 g_warning ("Cannot load backend '%s' since file '%s' cannot be read.",
203                            info->module_name,
204                            ev_module_get_path (EV_MODULE (info->module)));
205                 g_object_unref (G_OBJECT (info->module));
206                 info->module = NULL;
207
208                 return NULL;
209         }
210
211         document = EV_DOCUMENT (ev_module_new_object (EV_MODULE (info->module)));
212         g_type_module_unuse (info->module);
213
214         return document;
215 }
216
217 static EvBackendInfo *
218 get_document_backend_info (EvDocument *document)
219 {
220         GList *l;
221
222         for (l = ev_backends_list; l; l = g_list_next (l)) {
223                 EvBackendInfo *info;
224                 GType          type_id;
225
226                 info = (EvBackendInfo *)l->data;
227
228                 if (!info->module)
229                         continue;
230
231                 type_id = ev_module_get_object_type (EV_MODULE (info->module));
232
233                 if (G_TYPE_CHECK_INSTANCE_TYPE (document, type_id)) {
234                         return info;
235                 }
236         }
237
238         return NULL;
239 }
240
241 const gchar *
242 ev_backends_manager_get_document_module_name (EvDocument *document)
243 {
244         EvBackendInfo *info;
245
246         info = get_document_backend_info (document);
247         return info ? info->module_name : NULL;
248 }
249
250 static EvTypeInfo *
251 ev_type_info_new (const gchar *desc, const gchar **mime_types)
252 {
253         EvTypeInfo *info;
254
255         info = g_new (EvTypeInfo, 1);
256
257         info->desc = desc;
258         info->mime_types = mime_types;
259
260         return info;
261 }
262
263 EvTypeInfo *
264 ev_backends_manager_get_document_type_info (EvDocument *document)
265 {
266         EvBackendInfo *info;
267
268         info = get_document_backend_info (document);
269         return info ?
270                 ev_type_info_new (info->type_desc,
271                                   (const gchar **)info->mime_types)
272                 : NULL;
273 }
274
275 GList *
276 ev_backends_manager_get_all_types_info (void)
277 {
278         GList *l;
279         GList *retval = NULL;
280
281         for (l = ev_backends_list; l; l = g_list_next (l)) {
282                 EvBackendInfo *info;
283                 EvTypeInfo    *type_info;
284
285                 info = (EvBackendInfo *)l->data;
286
287                 type_info = ev_type_info_new (info->type_desc,
288                                               (const gchar **)info->mime_types);
289                 retval = g_list_prepend (retval, type_info);
290         }
291
292         return retval;
293 }