]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-backends-manager.c
Plugin system for backends. Fixes bug #351348.
[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         return TRUE;
141 }
142
143 gboolean
144 ev_backends_manager_init (void)
145 {
146         if (ev_backends_list)
147                 return FALSE;
148
149         return ev_backends_manager_load ();
150 }
151
152 void
153 ev_backends_manager_shutdown (void)
154 {
155         g_list_foreach (ev_backends_list, (GFunc)ev_backend_info_free, NULL);
156         g_list_free (ev_backends_list);
157         ev_backends_list = NULL;
158 }
159
160 static EvBackendInfo *
161 ev_backends_manager_get_backend_info (const gchar *mime_type)
162 {
163         GList *l;
164
165         for (l = ev_backends_list; l; l = g_list_next (l)) {
166                 EvBackendInfo *info;
167                 gint           i = 0;
168                 const char    *mime;
169                 
170                 info = (EvBackendInfo *)l->data;
171                 
172                 while ((mime = info->mime_types[i++])) {
173                         if (g_ascii_strcasecmp (mime, mime_type) == 0)
174                                 return info;
175                 }
176         }
177
178         return NULL;
179 }
180
181 EvDocument *
182 ev_backends_manager_get_document (const gchar *mime_type)
183 {
184         EvDocument    *document;
185         EvBackendInfo *info;
186
187         info = ev_backends_manager_get_backend_info (mime_type);
188         if (!info)
189                 return NULL;
190
191         if (!info->module) {
192                 gchar *path;
193                 
194                 path = g_module_build_path (EV_BACKENDSDIR, info->module_name);
195                 info->module = G_TYPE_MODULE (ev_module_new (path));
196                 g_free (path);
197         }
198         
199         if (!g_type_module_use (info->module)) {
200                 g_warning ("Cannot load backend '%s' since file '%s' cannot be read.",
201                            info->module_name,
202                            ev_module_get_path (EV_MODULE (info->module)));
203                 g_object_unref (G_OBJECT (info->module));
204                 info->module = NULL;
205
206                 return NULL;
207         }
208
209         document = EV_DOCUMENT (ev_module_new_object (EV_MODULE (info->module)));
210         g_type_module_unuse (info->module);
211
212         return document;
213 }
214
215 static EvBackendInfo *
216 get_document_backend_info (EvDocument *document)
217 {
218         GList *l;
219
220         for (l = ev_backends_list; l; l = g_list_next (l)) {
221                 EvBackendInfo *info;
222                 GType          type_id;
223
224                 info = (EvBackendInfo *)l->data;
225
226                 if (!info->module)
227                         continue;
228
229                 type_id = ev_module_get_object_type (EV_MODULE (info->module));
230
231                 if (G_TYPE_CHECK_INSTANCE_TYPE (document, type_id)) {
232                         return info;
233                 }
234         }
235
236         return NULL;
237 }
238
239 const gchar *
240 ev_backends_manager_get_document_module_name (EvDocument *document)
241 {
242         EvBackendInfo *info;
243
244         info = get_document_backend_info (document);
245         return info ? info->module_name : NULL;
246 }
247
248 static EvTypeInfo *
249 ev_type_info_new (const gchar *desc, const gchar **mime_types)
250 {
251         EvTypeInfo *info;
252
253         info = g_new (EvTypeInfo, 1);
254
255         info->desc = desc;
256         info->mime_types = mime_types;
257
258         return info;
259 }
260
261 EvTypeInfo *
262 ev_backends_manager_get_document_type_info (EvDocument *document)
263 {
264         EvBackendInfo *info;
265
266         info = get_document_backend_info (document);
267         return info ?
268                 ev_type_info_new (info->type_desc,
269                                   (const gchar **)info->mime_types)
270                 : NULL;
271 }
272
273 GList *
274 ev_backends_manager_get_all_types_info (void)
275 {
276         GList *l;
277         GList *retval = NULL;
278
279         for (l = ev_backends_list; l; l = g_list_next (l)) {
280                 EvBackendInfo *info;
281                 EvTypeInfo    *type_info;
282
283                 info = (EvBackendInfo *)l->data;
284
285                 type_info = ev_type_info_new (info->type_desc,
286                                               (const gchar **)info->mime_types);
287                 retval = g_list_prepend (retval, type_info);
288         }
289
290         return retval;
291 }