1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2008 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <string.h>
24 #include <glib/gi18n.h>
25 #include <glib.h>
26 #include <glib-object.h>
27 #include <gobject/gvaluecollector.h>
28 #include "glib-utils.h"
29 #include "gth-duplicable.h"
30 #include "gth-file-source-vfs.h"
31 #include "gth-filter.h"
32 #include "gth-main.h"
33 #include "gth-metadata-provider.h"
34 #include "gth-user-dir.h"
35 #include "gth-preferences.h"
36 #include "gth-shortcut.h"
37 #include "gtk-utils.h"
38 #include "pixbuf-io.h"
39 #include "typedefs.h"
40 
41 #ifdef GDK_WINDOWING_X11
42 #include <gdk/gdkx.h>
43 #endif
44 
45 
46 static GMutex register_mutex;
47 
48 
49 typedef struct {
50 	GType        object_type;
51 	guint        n_params;
52 	const char **names;
53 	GValue      *values;
54 } GthTypeSpec;
55 
56 
57 static GthTypeSpec *
gth_type_spec_new(GType object_type)58 gth_type_spec_new (GType object_type)
59 {
60 	GthTypeSpec *spec;
61 
62 	spec = g_new0 (GthTypeSpec, 1);
63 	spec->object_type = object_type;
64 	spec->n_params = 0;
65 	spec->names = NULL;
66 	spec->values = NULL;
67 
68 	return spec;
69 }
70 
71 
72 static void
gth_type_spec_free(GthTypeSpec * spec)73 gth_type_spec_free (GthTypeSpec *spec)
74 {
75 	while (spec->n_params--)
76 		g_value_unset (&spec->values[spec->n_params]);
77 	g_free (spec->names);
78 	g_free (spec->values);
79 	g_free (spec);
80 }
81 
82 
83 static GObject *
gth_type_spec_create_object(GthTypeSpec * spec,const char * object_id)84 gth_type_spec_create_object (GthTypeSpec *spec,
85 			     const char  *object_id)
86 {
87 	GObject *object;
88 
89 	object = g_object_new_with_properties (spec->object_type,
90 					       spec->n_params,
91 					       spec->names,
92 					       spec->values);
93 	if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), "id"))
94 		g_object_set (object, "id", object_id, NULL);
95 
96 	return object;
97 }
98 
99 
100 static GthMain *Main = NULL;
101 
102 
103 struct _GthMainPrivate {
104 	GList               *file_sources;
105 	GList               *metadata_provider;
106 	GPtrArray           *metadata_category;
107 	GPtrArray           *metadata_info;
108 	GHashTable          *metadata_info_hash;
109 	gboolean             metadata_info_sorted;
110 	GPtrArray           *shortcut_category_v;
111 	GHashTable          *shortcut_category_h;
112 	GHashTable          *sort_types;
113 	GHashTable          *image_loaders;
114 	GHashTable          *types;
115 	GHashTable          *classes;
116 	GHashTable          *objects_order;
117 	GBookmarkFile       *bookmarks;
118 	GthFilterFile       *filters;
119 	GthTagsFile         *tags;
120 	GthMonitor          *monitor;
121 	GthExtensionManager *extension_manager;
122 	GthColorManager     *color_manager;
123 };
124 
125 
G_DEFINE_TYPE_WITH_CODE(GthMain,gth_main,G_TYPE_OBJECT,G_ADD_PRIVATE (GthMain))126 G_DEFINE_TYPE_WITH_CODE (GthMain,
127 			 gth_main,
128 			 G_TYPE_OBJECT,
129 			 G_ADD_PRIVATE (GthMain))
130 
131 
132 static void
133 gth_main_finalize (GObject *object)
134 {
135 	GthMain *gth_main = GTH_MAIN (object);
136 
137 	_g_object_list_unref (gth_main->priv->file_sources);
138 
139 	g_hash_table_unref (gth_main->priv->metadata_info_hash);
140 	g_ptr_array_unref (gth_main->priv->metadata_category);
141 	g_ptr_array_unref (gth_main->priv->metadata_info);
142 	g_list_foreach (gth_main->priv->metadata_provider, (GFunc) g_object_unref, NULL);
143 	g_list_free (gth_main->priv->metadata_provider);
144 
145 	g_ptr_array_unref (gth_main->priv->shortcut_category_v);
146 	g_hash_table_unref (gth_main->priv->shortcut_category_h);
147 
148 	if (gth_main->priv->sort_types != NULL)
149 		g_hash_table_unref (gth_main->priv->sort_types);
150 	if (gth_main->priv->image_loaders != NULL)
151 		g_hash_table_unref (gth_main->priv->image_loaders);
152 	if (gth_main->priv->types != NULL)
153 		g_hash_table_unref (gth_main->priv->types);
154 	if (gth_main->priv->classes != NULL)
155 		g_hash_table_unref (gth_main->priv->classes);
156 	if (gth_main->priv->objects_order != NULL)
157 		g_hash_table_unref (gth_main->priv->objects_order);
158 
159 	if (gth_main->priv->bookmarks != NULL)
160 		g_bookmark_file_free (gth_main->priv->bookmarks);
161 
162 	_g_object_unref (gth_main->priv->monitor);
163 	_g_object_unref (gth_main->priv->extension_manager);
164 	_g_object_unref (gth_main->priv->color_manager);
165 	gth_filter_file_free (gth_main->priv->filters);
166 	gth_tags_file_free (gth_main->priv->tags);
167 
168 	G_OBJECT_CLASS (gth_main_parent_class)->finalize (object);
169 }
170 
171 
172 static void
gth_main_class_init(GthMainClass * class)173 gth_main_class_init (GthMainClass *class)
174 {
175 	GObjectClass *object_class;
176 
177 	object_class = (GObjectClass*) class;
178 	object_class->finalize = gth_main_finalize;
179 }
180 
181 
182 static void
gth_main_init(GthMain * main)183 gth_main_init (GthMain *main)
184 {
185 	main->priv = gth_main_get_instance_private (main);
186 	main->priv->file_sources = NULL;
187 	main->priv->metadata_provider = NULL;
188 	main->priv->metadata_category = g_ptr_array_new ();
189 	main->priv->metadata_info = g_ptr_array_new ();
190 	main->priv->metadata_info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
191 	main->priv->metadata_info_sorted = FALSE;
192 	main->priv->shortcut_category_v = g_ptr_array_new ();
193 	main->priv->shortcut_category_h = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
194 	main->priv->sort_types = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
195 	main->priv->image_loaders = g_hash_table_new_full (g_str_hash,
196 						           (GEqualFunc) g_content_type_equals,
197 						           g_free,
198 						           NULL);
199 	main->priv->types = NULL;
200 	main->priv->classes = NULL;
201 	main->priv->objects_order = NULL;
202 	main->priv->bookmarks = NULL;
203 	main->priv->filters = NULL;
204 	main->priv->tags = NULL;
205 	main->priv->monitor = NULL;
206 	main->priv->extension_manager = gth_extension_manager_new ();
207 	main->priv->color_manager = NULL;
208 }
209 
210 
211 void
gth_main_initialize(void)212 gth_main_initialize (void)
213 {
214 	if (Main != NULL)
215 		return;
216 
217 	Main = (GthMain*) g_object_new (GTH_TYPE_MAIN, NULL);
218 }
219 
220 
221 void
gth_main_release(void)222 gth_main_release (void)
223 {
224 	if (Main != NULL)
225 		g_object_unref (Main);
226 }
227 
228 
229 void
gth_main_register_file_source(GType file_source_type)230 gth_main_register_file_source (GType file_source_type)
231 {
232 	GObject *file_source;
233 
234 	g_mutex_lock (&register_mutex);
235 
236 	file_source = g_object_new (file_source_type, NULL);
237 	Main->priv->file_sources = g_list_append (Main->priv->file_sources, file_source);
238 
239 	g_mutex_unlock (&register_mutex);
240 }
241 
242 
243 GthFileSource *
gth_main_get_file_source_for_uri(const char * uri)244 gth_main_get_file_source_for_uri (const char *uri)
245 {
246 	GthFileSource *file_source = NULL;
247 	GList         *scan;
248 
249 	for (scan = Main->priv->file_sources; scan; scan = scan->next) {
250 		GthFileSource *registered_file_source = scan->data;
251 
252 		if (gth_file_source_supports_scheme (registered_file_source, uri)) {
253 			file_source = g_object_new (G_OBJECT_TYPE (registered_file_source), NULL);
254 			break;
255 		}
256 	}
257 
258 	if (file_source == NULL)
259 		file_source = g_object_new (GTH_TYPE_FILE_SOURCE_VFS, NULL);
260 
261 	return file_source;
262 }
263 
264 
265 GthFileSource *
gth_main_get_file_source(GFile * file)266 gth_main_get_file_source (GFile *file)
267 {
268 	char          *uri;
269 	GthFileSource *file_source;
270 
271 	if (file == NULL)
272 		return NULL;
273 
274 	uri = g_file_get_uri (file);
275 	file_source = gth_main_get_file_source_for_uri (uri);
276 	g_free (uri);
277 
278 	return file_source;
279 }
280 
281 
282 char *
gth_main_get_source_scheme(const char * uri)283 gth_main_get_source_scheme (const char *uri)
284 {
285 	GList *scan;
286 
287 	for (scan = Main->priv->file_sources; scan; scan = scan->next) {
288 		GthFileSource *registered_file_source = scan->data;
289 
290 		if (gth_file_source_supports_scheme (registered_file_source, uri))
291 			return _g_uri_get_scheme (uri);
292 	}
293 
294 	return g_strdup ("file");
295 }
296 
297 
298 GList *
gth_main_get_all_file_sources(void)299 gth_main_get_all_file_sources (void)
300 {
301 	return Main->priv->file_sources;
302 }
303 
304 
305 #define MAX_ENTRY_POINTS_PER_SOURCE 1000
306 
307 
308 GList *
gth_main_get_all_entry_points(void)309 gth_main_get_all_entry_points (void)
310 {
311 	GList *list = NULL;
312 	int    sort_order = 0;
313 	GList *scan;
314 
315 	for (scan = gth_main_get_all_file_sources (); scan; scan = scan->next) {
316 		GthFileSource *file_source = scan->data;
317 		GList         *entry_points;
318 		GList         *scan_entry;
319 
320 		entry_points = gth_file_source_get_entry_points (file_source);
321 		for (scan_entry = entry_points; scan_entry; scan_entry = scan_entry->next) {
322 			GthFileData *file_data = scan_entry->data;
323 			g_file_info_set_sort_order (file_data->info, sort_order++);
324 		}
325 
326 		list = g_list_concat (list, entry_points);
327 		sort_order += MAX_ENTRY_POINTS_PER_SOURCE;
328 	}
329 
330 	return list;
331 }
332 
333 
334 GFile *
gth_main_get_nearest_entry_point(GFile * file)335 gth_main_get_nearest_entry_point (GFile *file)
336 {
337 	GList *list;
338 	GList *scan;
339 	GList *entries;
340 	char  *nearest_uri;
341 	char  *uri;
342 	int    file_uri_len;
343 	int    min_diff;
344 	GFile *nearest;
345 
346 	entries = NULL;
347 	list = gth_main_get_all_entry_points ();
348 	for (scan = list; scan; scan = scan->next) {
349 		GthFileData *entry_point = scan->data;
350 
351 		if (_g_file_is_parent (entry_point->file, file))
352 			entries = g_list_prepend (entries, g_file_get_uri (entry_point->file));
353 	}
354 
355 	nearest_uri = NULL;
356 	uri = g_file_get_uri (file);
357 	file_uri_len = strlen (uri);
358 	min_diff = 0;
359 	for (scan = entries; scan; scan = scan->next) {
360 		char *entry_uri = scan->data;
361 		int   entry_len;
362 		int   diff;
363 
364 		entry_len = strlen (entry_uri);
365 		diff = abs (entry_len - file_uri_len);
366 		if ((scan == entries) || (diff < min_diff)) {
367 			min_diff = diff;
368 			nearest_uri = entry_uri;
369 		}
370 	}
371 	g_free (uri);
372 
373 	nearest = NULL;
374 	if (nearest_uri != NULL)
375 		nearest = g_file_new_for_uri (nearest_uri);
376 
377 	_g_string_list_free (entries);
378 	_g_object_list_unref (list);
379 
380 	return nearest;
381 }
382 
383 
384 char *
gth_main_get_gio_uri(const char * uri)385 gth_main_get_gio_uri (const char *uri)
386 {
387 	GthFileSource *file_source;
388 	GFile         *file;
389 	GFile         *gio_file;
390 	char          *gio_uri;
391 
392 	file_source = gth_main_get_file_source_for_uri (uri);
393 	file = g_file_new_for_uri (uri);
394 	gio_file = gth_file_source_to_gio_file (file_source, file);
395 	gio_uri = g_file_get_uri (gio_file);
396 
397 	g_object_unref (gio_file);
398 	g_object_unref (file);
399 	g_object_unref (file_source);
400 
401 	return gio_uri;
402 }
403 
404 
405 GFile *
gth_main_get_gio_file(GFile * file)406 gth_main_get_gio_file (GFile *file)
407 {
408 	GthFileSource *file_source;
409 	GFile         *gio_file;
410 
411 	file_source = gth_main_get_file_source (file);
412 	gio_file = gth_file_source_to_gio_file (file_source, file);
413 	g_object_unref (file_source);
414 
415 	return gio_file;
416 }
417 
418 
419 void
gth_main_register_metadata_category(GthMetadataCategory * metadata_category)420 gth_main_register_metadata_category (GthMetadataCategory *metadata_category)
421 {
422 	int i;
423 
424 	g_mutex_lock (&register_mutex);
425 
426 	for (i = 0; metadata_category[i].id != NULL; i++)
427 		if (gth_main_get_metadata_category (metadata_category[i].id) == NULL)
428 			g_ptr_array_add (Main->priv->metadata_category, &metadata_category[i]);
429 
430 	g_mutex_unlock (&register_mutex);
431 }
432 
433 
434 static GMutex metadata_info_mutex;
435 
436 
437 GthMetadataInfo *
gth_main_register_metadata_info(GthMetadataInfo * metadata_info)438 gth_main_register_metadata_info (GthMetadataInfo *metadata_info)
439 {
440 	GthMetadataInfo *info;
441 
442 	if ((metadata_info->display_name != NULL) && (strstr (metadata_info->display_name, "0x") != NULL))
443 		metadata_info->flags = GTH_METADATA_ALLOW_NOWHERE;
444 
445 	g_mutex_lock (&metadata_info_mutex);
446 
447 	info = gth_metadata_info_dup (metadata_info);
448 	g_ptr_array_add (Main->priv->metadata_info, info);
449 	g_hash_table_insert (Main->priv->metadata_info_hash, (gpointer) info->id, info);
450 	Main->priv->metadata_info_sorted = FALSE;
451 
452 	g_mutex_unlock (&metadata_info_mutex);
453 
454 	return info;
455 }
456 
457 
458 void
gth_main_register_metadata_info_v(GthMetadataInfo metadata_info[])459 gth_main_register_metadata_info_v (GthMetadataInfo metadata_info[])
460 {
461 	int i;
462 
463 	g_mutex_lock (&metadata_info_mutex);
464 
465 	for (i = 0; metadata_info[i].id != NULL; i++)
466 		if ((metadata_info[i].display_name == NULL) || (strstr (metadata_info[i].display_name, "0x") == NULL)) {
467 			if (metadata_info[i].sort_order <= 0)
468 				metadata_info[i].sort_order = 500;
469 			g_ptr_array_add (Main->priv->metadata_info, &metadata_info[i]);
470 			g_hash_table_insert (Main->priv->metadata_info_hash, (gpointer) (&metadata_info[i])->id, &metadata_info[i]);
471 		}
472 
473 	g_mutex_unlock (&metadata_info_mutex);
474 }
475 
476 
477 void
gth_main_register_metadata_provider(GType metadata_provider_type)478 gth_main_register_metadata_provider (GType metadata_provider_type)
479 {
480 	GObject *metadata;
481 
482 	g_mutex_lock (&register_mutex);
483 
484 	metadata = g_object_new (metadata_provider_type, NULL);
485 	Main->priv->metadata_provider = g_list_append (Main->priv->metadata_provider, metadata);
486 
487 	g_mutex_unlock (&register_mutex);
488 }
489 
490 
491 GList *
gth_main_get_all_metadata_providers(void)492 gth_main_get_all_metadata_providers (void)
493 {
494 	return Main->priv->metadata_provider;
495 }
496 
497 
498 static int
metadata_info_sort_func(gconstpointer a,gconstpointer b)499 metadata_info_sort_func (gconstpointer a,
500 			 gconstpointer b)
501 {
502 	GthMetadataInfo *info_a = *((GthMetadataInfo **) a);
503 	GthMetadataInfo *info_b = *((GthMetadataInfo **) b);
504 	const char      *name_a;
505 	const char      *name_b;
506 
507 	name_a = info_a->display_name;
508 	if (name_a == NULL)
509 		name_a = info_a->id;
510 
511 	name_b = info_b->display_name;
512 	if (name_b == NULL)
513 		name_b = info_b->id;
514 
515 	return g_utf8_collate (name_a, name_b);
516 }
517 
518 
519 char **
gth_main_get_metadata_attributes(const char * mask)520 gth_main_get_metadata_attributes (const char *mask)
521 {
522 	GList                  *list = NULL;
523 	GFileAttributeMatcher  *matcher;
524 	int                     i;
525 	int                     n;
526 	GList                  *scan;
527 	char                  **values;
528 
529 	g_mutex_lock (&metadata_info_mutex);
530 
531 	if (! Main->priv->metadata_info_sorted) {
532 		g_ptr_array_sort (Main->priv->metadata_info, metadata_info_sort_func);
533 		Main->priv->metadata_info_sorted = TRUE;
534 	}
535 
536 	matcher = g_file_attribute_matcher_new (mask);
537 	for (n = 0, i = 0; i < Main->priv->metadata_info->len; i++) {
538 		GthMetadataInfo *metadata_info = g_ptr_array_index (Main->priv->metadata_info, i);
539 
540 		if (g_file_attribute_matcher_matches (matcher, metadata_info->id)) {
541 			list = g_list_prepend (list, (char *) metadata_info->id);
542 			n++;
543 		}
544 	}
545 	list = g_list_reverse (list);
546 
547 	g_mutex_unlock (&metadata_info_mutex);
548 
549 	values = g_new (char *, n + 1);
550 	for (i = 0, scan = list; scan; i++, scan = scan->next)
551 		values[i] = g_strdup (scan->data);
552 	values[n] = NULL;
553 
554 	g_list_free (list);
555 	g_file_attribute_matcher_unref (matcher);
556 
557 	return values;
558 }
559 
560 
561 GthMetadataProvider *
gth_main_get_metadata_reader(const char * id,const char * mime_type)562 gth_main_get_metadata_reader (const char *id,
563 			      const char *mime_type)
564 {
565 	GthMetadataProvider *metadata = NULL;
566 	GList               *scan;
567 	const char          *attribute_v[] = { id, NULL };
568 
569 	for (scan = Main->priv->metadata_provider; scan; scan = scan->next) {
570 		GthMetadataProvider *registered_metadata = scan->data;
571 
572 		if (gth_metadata_provider_can_read (registered_metadata, mime_type, (char **)attribute_v)) {
573 			metadata = g_object_new (G_OBJECT_TYPE (registered_metadata), NULL);
574 			break;
575 		}
576 	}
577 
578 	return metadata;
579 }
580 
581 
582 GthMetadataProvider *
gth_main_get_metadata_writer(const char * id,const char * mime_type)583 gth_main_get_metadata_writer (const char *id,
584 			      const char *mime_type)
585 {
586 	GthMetadataProvider *metadata = NULL;
587 	GList               *scan;
588 	const char          *attribute_v[] = { id, NULL };
589 
590 	for (scan = Main->priv->metadata_provider; scan; scan = scan->next) {
591 		GthMetadataProvider *registered_metadata = scan->data;
592 
593 		if (gth_metadata_provider_can_write (registered_metadata, mime_type, (char **)attribute_v)) {
594 			metadata = g_object_new (G_OBJECT_TYPE (registered_metadata), NULL);
595 			break;
596 		}
597 	}
598 
599 	return metadata;
600 }
601 
602 
603 GthMetadataCategory *
gth_main_get_metadata_category(const char * id)604 gth_main_get_metadata_category (const char *id)
605 {
606 	int i;
607 
608 	if (id == NULL)
609 		return NULL;
610 
611 	for (i = 0; i < Main->priv->metadata_category->len; i++) {
612 		GthMetadataCategory *category;
613 
614 		category = g_ptr_array_index (Main->priv->metadata_category, i);
615 		if (strcmp (category->id, id) == 0)
616 			return category;
617 	}
618 
619 	return NULL;
620 }
621 
622 
623 GthMetadataInfo *
gth_main_get_metadata_info(const char * id)624 gth_main_get_metadata_info (const char *id)
625 {
626 	GthMetadataInfo *info;
627 
628 	if (id == NULL)
629 		return NULL;
630 
631 	info = g_hash_table_lookup (Main->priv->metadata_info_hash, id);
632 
633 	return info;
634 }
635 
636 
637 GList *
gth_main_get_all_metadata_info(void)638 gth_main_get_all_metadata_info (void)
639 {
640 	GList *list = NULL;
641 	int    i;
642 
643 	g_mutex_lock (&metadata_info_mutex);
644 
645 	for (i = 0; i < Main->priv->metadata_info->len; i++) {
646 		GthMetadataInfo *metadata_info = g_ptr_array_index (Main->priv->metadata_info, i);
647 
648 		list = g_list_prepend (list, metadata_info);
649 	}
650 	list = g_list_reverse (list);
651 
652 	g_mutex_unlock (&metadata_info_mutex);
653 
654 	return list;
655 }
656 
657 
658 GthShortcutCategory *
gth_main_get_shortcut_category(const char * id)659 gth_main_get_shortcut_category (const char *id)
660 {
661 	return g_hash_table_lookup (Main->priv->shortcut_category_h, id);
662 }
663 
664 
665 GPtrArray *
gth_main_get_shortcut_categories(void)666 gth_main_get_shortcut_categories (void)
667 {
668 	return Main->priv->shortcut_category_v;
669 }
670 
671 
672 void
gth_main_register_shortcut_category(GthShortcutCategory * shortcut_category,int n_categories)673 gth_main_register_shortcut_category (GthShortcutCategory *shortcut_category,
674 				     int                  n_categories)
675 {
676 	int i;
677 
678 	g_mutex_lock (&register_mutex);
679 	for (i = 0; i < n_categories; i++) {
680 		if (gth_main_get_shortcut_category (shortcut_category[i].id) == NULL) {
681 			g_ptr_array_add (Main->priv->shortcut_category_v, &shortcut_category[i]);
682 			g_hash_table_insert (Main->priv->shortcut_category_h, shortcut_category[i].id, &shortcut_category[i]);
683 		}
684 	}
685 	g_mutex_unlock (&register_mutex);
686 }
687 
688 
689 void
gth_main_register_sort_type(GthFileDataSort * sort_type)690 gth_main_register_sort_type (GthFileDataSort *sort_type)
691 {
692 	g_mutex_lock (&register_mutex);
693 	g_hash_table_insert (Main->priv->sort_types, (gpointer) sort_type->name, sort_type);
694 	g_mutex_unlock (&register_mutex);
695 }
696 
697 
698 GthFileDataSort *
gth_main_get_sort_type(const char * name)699 gth_main_get_sort_type (const char *name)
700 {
701 	GthFileDataSort *retval =  NULL;
702 
703 	if (name == NULL)
704 		return NULL;
705 
706 	retval = g_hash_table_lookup (Main->priv->sort_types, name);
707 
708 	if (retval != NULL)
709 		return retval;
710 	else
711 		return g_hash_table_lookup (Main->priv->sort_types, "file::name");
712 }
713 
714 
715 static void
collect_sort_types(gpointer key,gpointer value,gpointer user_data)716 collect_sort_types (gpointer key,
717 		    gpointer value,
718 		    gpointer user_data)
719 {
720 	GList           **sort_types = user_data;
721 	GthFileDataSort  *sort_type = value;
722 
723 	*sort_types = g_list_prepend (*sort_types, sort_type);
724 }
725 
726 
727 static gboolean
campare_sort_types(GthFileDataSort * type1,GthFileDataSort * type2)728 campare_sort_types (GthFileDataSort *type1,
729 		    GthFileDataSort *type2)
730 {
731 	return g_utf8_collate (type1->display_name, type2->display_name);
732 }
733 
734 
735 GList *
gth_main_get_all_sort_types(void)736 gth_main_get_all_sort_types (void)
737 {
738 	GList *sort_types = NULL;
739 
740 	g_hash_table_foreach (Main->priv->sort_types, collect_sort_types, &sort_types);
741 	return g_list_sort (sort_types, (GCompareFunc) campare_sort_types);
742 }
743 
744 
745 static GthTypeSpec *
_gth_main_create_type_spec(GType object_type,va_list var_args)746 _gth_main_create_type_spec (GType       object_type,
747 			    va_list     var_args)
748 {
749 	GObject     *object;
750 	GthTypeSpec *type_spec;
751 	const char  *name;
752 	guint        max_params = 16;
753 
754 	type_spec = gth_type_spec_new (object_type);
755 
756     	object = g_object_new (object_type, NULL);
757 
758   	while ((name = va_arg (var_args, char *)) != NULL) {
759 		GParamSpec *pspec;
760 		char       *error = NULL;
761 
762 		if (type_spec->n_params == max_params - 1) {
763 			g_warning ("%s: too many params (max: %d)", G_STRFUNC, max_params);
764 			break;
765 		}
766 
767 		if (type_spec->names == NULL) {
768 			int i;
769 
770 			type_spec->names = g_new (const char *, max_params);
771 			for (i = 0; i < max_params; i++)
772 				type_spec->names[i] = NULL;
773 		}
774 
775 		if (type_spec->values == NULL) {
776 			int i;
777 
778 			type_spec->values = g_new (GValue, max_params);
779 			for (i = 0; i < max_params; i++) {
780 				type_spec->values[i].g_type = 0;
781 			}
782 		}
783 
784 		pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
785 		if (pspec == NULL) {
786 			g_warning ("%s: object class `%s' has no property named `%s'",
787 				   G_STRFUNC,
788 				   g_type_name (object_type),
789 				   name);
790 			break;
791 		}
792 		type_spec->names[type_spec->n_params] = name;
793 		g_value_init (&type_spec->values[type_spec->n_params], G_PARAM_SPEC_VALUE_TYPE (pspec));
794 		G_VALUE_COLLECT (&type_spec->values[type_spec->n_params], var_args, 0, &error);
795 		if (error != NULL) {
796 			g_warning ("%s: %s", G_STRFUNC, error);
797 			g_free (error);
798 			g_value_unset (&type_spec->values[type_spec->n_params]);
799 			break;
800 		}
801 		type_spec->n_params++;
802 	}
803 
804 	g_object_unref (object);
805 
806 	return type_spec;
807 }
808 
809 
810 static void
_register_image_loader_func(GthImageLoaderFunc loader,GthImageFormat native_format,const char * mime_type)811 _register_image_loader_func (GthImageLoaderFunc  loader,
812 			     GthImageFormat      native_format,
813 			     const char         *mime_type)
814 {
815 	char *key;
816 
817 	key = g_strdup_printf ("%s-%d", mime_type, native_format);
818 	g_hash_table_insert (Main->priv->image_loaders, (gpointer) key, loader);
819 }
820 
821 
822 void
gth_main_register_image_loader_func(GthImageLoaderFunc loader,GthImageFormat native_format,...)823 gth_main_register_image_loader_func (GthImageLoaderFunc  loader,
824 				     GthImageFormat      native_format,
825 				     ...)
826 {
827 	va_list     var_args;
828 	const char *mime_type;
829 
830 	g_mutex_lock (&register_mutex);
831 
832 	va_start (var_args, native_format);
833   	while ((mime_type = va_arg (var_args, const char *)) != NULL)
834   		_register_image_loader_func (loader, native_format, mime_type);
835 	va_end (var_args);
836 
837 	g_mutex_unlock (&register_mutex);
838 }
839 
840 
841 void
gth_main_register_image_loader_func_v(GthImageLoaderFunc loader,GthImageFormat native_format,const char ** mime_types)842 gth_main_register_image_loader_func_v (GthImageLoaderFunc   loader,
843 				       GthImageFormat       native_format,
844 				       const char         **mime_types)
845 {
846 	int i;
847 
848 	g_mutex_lock (&register_mutex);
849 
850 	for (i = 0; mime_types[i] != NULL; i++)
851 		_register_image_loader_func (loader, native_format, mime_types[i]);
852 
853 	g_mutex_unlock (&register_mutex);
854 }
855 
856 
857 GthImageLoaderFunc
gth_main_get_image_loader_func(const char * mime_type,GthImageFormat preferred_format)858 gth_main_get_image_loader_func (const char     *mime_type,
859 				GthImageFormat  preferred_format)
860 {
861 	GthImageLoaderFunc  loader;
862 	char               *key;
863 	int                 format;
864 
865 	/* give priority to the preferred format */
866 
867 	key = g_strdup_printf ("%s-%d", mime_type, preferred_format);
868 	loader = g_hash_table_lookup (Main->priv->image_loaders, key);
869 
870 	/* if the preferred format is not available, search another
871 	 * format. */
872 
873 	for (format = 0; (loader == NULL) && (format < GTH_IMAGE_N_FORMATS); format++) {
874 		if (format == preferred_format)
875 			continue;
876 		g_free (key);
877 		key = g_strdup_printf ("%s-%d", mime_type, format);
878 		loader = g_hash_table_lookup (Main->priv->image_loaders, key);
879 	}
880 
881 	g_free (key);
882 
883 	return loader;
884 }
885 
886 
887 GthImageSaver *
gth_main_get_image_saver(const char * mime_type)888 gth_main_get_image_saver (const char *mime_type)
889 {
890 	GArray *savers;
891 	int     i;
892 
893 	savers = gth_main_get_type_set ("image-saver");
894 	if (savers == NULL)
895 		return NULL;
896 
897 	for (i = 0; i < savers->len; i++) {
898 		GType           saver_type;
899 		GthImageSaver *saver;
900 
901 		saver_type = g_array_index (savers, GType, i);
902 		saver = g_object_new (saver_type, NULL);
903 		if (gth_image_saver_can_save (saver, mime_type))
904 			return saver;
905 
906 		g_object_unref (saver);
907 	}
908 
909 	return NULL;
910 }
911 
912 
913 GthTest *
gth_main_get_general_filter(void)914 gth_main_get_general_filter (void)
915 {
916 	GSettings *settings;
917 	char      *filter_name;
918 	GthTest   *filter;
919 
920 	settings = g_settings_new (GTHUMB_BROWSER_SCHEMA);
921 	filter_name = g_settings_get_string (settings, PREF_BROWSER_GENERAL_FILTER);
922 	filter = gth_main_get_registered_object (GTH_TYPE_TEST, filter_name);
923 
924 	g_free (filter_name);
925 	g_object_unref (settings);
926 
927 	return filter;
928 }
929 
930 
931 GthTest *
gth_main_add_general_filter(GthTest * original_filter)932 gth_main_add_general_filter (GthTest *original_filter)
933 {
934 	GthTest *test;
935 
936 	if (original_filter == NULL)
937 		test = gth_main_get_general_filter ();
938 	else
939 		test = (GthTest *) gth_duplicable_duplicate (GTH_DUPLICABLE (original_filter));
940 
941 	if (! GTH_IS_FILTER (test)) {
942 		GthTest   *new_chain;
943 		GthFilter *filter;
944 
945 		filter = gth_filter_new ();
946 
947 		new_chain = gth_test_chain_new (GTH_MATCH_TYPE_ALL, NULL);
948 		gth_test_chain_add_test (GTH_TEST_CHAIN (new_chain), test);
949 
950 		if (strncmp (gth_test_get_id (test), "file::type::", 12) != 0) {
951 			GthTest *file_type_filter;
952 
953 			file_type_filter = gth_main_get_general_filter ();
954 			gth_test_chain_add_test (GTH_TEST_CHAIN (new_chain), file_type_filter);
955 			g_object_unref (file_type_filter);
956 		}
957 		gth_filter_set_test (filter, GTH_TEST_CHAIN (new_chain));
958 		g_object_unref (new_chain);
959 
960 		g_object_unref (test);
961 		test = (GthTest*) filter;
962 	}
963 	else {
964 		GthFilter    *filter;
965 		GthTestChain *filter_test;
966 
967 		filter = (GthFilter *) gth_duplicable_duplicate (GTH_DUPLICABLE (test));
968 		filter_test = gth_filter_get_test (filter);
969 		if ((filter_test == NULL) || ! gth_test_chain_has_type_test (filter_test)) {
970 			GthTest *new_filter_test;
971 			GthTest *general_filter;
972 
973 			new_filter_test = gth_test_chain_new (GTH_MATCH_TYPE_ALL, NULL);
974 			if (filter_test != NULL)
975 				gth_test_chain_add_test (GTH_TEST_CHAIN (new_filter_test), GTH_TEST (filter_test));
976 
977 			general_filter = gth_main_get_general_filter ();
978 			gth_test_chain_add_test (GTH_TEST_CHAIN (new_filter_test), general_filter);
979 			g_object_unref (general_filter);
980 
981 			gth_filter_set_test (filter, GTH_TEST_CHAIN (new_filter_test));
982 			g_object_unref (new_filter_test);
983 		}
984 
985 		if (filter_test != NULL)
986 			g_object_unref (filter_test);
987 		g_object_unref (test);
988 
989 		test = (GthTest*) filter;
990 	}
991 
992 	return test;
993 }
994 
995 
996 static void
_g_destroy_array(GArray * array)997 _g_destroy_array (GArray *array)
998 {
999 	g_array_free (array, TRUE);
1000 }
1001 
1002 
1003 void
gth_main_register_type(const char * set_name,GType object_type)1004 gth_main_register_type (const char *set_name,
1005 			GType       object_type)
1006 {
1007 	GArray *set;
1008 
1009 	g_mutex_lock (&register_mutex);
1010 
1011 	if (Main->priv->types == NULL)
1012 		Main->priv->types = g_hash_table_new_full (g_str_hash,
1013 							   g_str_equal,
1014 							   (GDestroyNotify) g_free,
1015 							   (GDestroyNotify) _g_destroy_array);
1016 
1017 	set = g_hash_table_lookup (Main->priv->types, set_name);
1018 	if (set == NULL) {
1019 		set = g_array_new (FALSE, FALSE, sizeof (GType));
1020 		g_hash_table_insert (Main->priv->types, g_strdup (set_name), set);
1021 	}
1022 
1023 	g_array_append_val (set, object_type);
1024 
1025 	g_mutex_unlock (&register_mutex);
1026 }
1027 
1028 
1029 GArray *
gth_main_get_type_set(const char * set_name)1030 gth_main_get_type_set (const char *set_name)
1031 {
1032 	return g_hash_table_lookup (Main->priv->types, set_name);
1033 }
1034 
1035 
1036 static void
g_ptr_array_destroy(gpointer array)1037 g_ptr_array_destroy (gpointer array)
1038 {
1039 	g_ptr_array_unref ((GPtrArray *) array);
1040 }
1041 
1042 
1043 void
gth_main_register_object(GType superclass_type,const char * object_id,GType object_type,...)1044 gth_main_register_object (GType       superclass_type,
1045 			  const char *object_id,
1046 			  GType       object_type,
1047 			  ...)
1048 {
1049 	const char  *superclass_name;
1050 	GHashTable  *object_hash;
1051 	GPtrArray   *object_order;
1052 	va_list      var_args;
1053 	GthTypeSpec *spec;
1054 	char        *id;
1055 
1056 	g_mutex_lock (&register_mutex);
1057 
1058 	if (object_id == NULL)
1059 		object_id = g_type_name (object_type);
1060 
1061 	if (Main->priv->classes == NULL) {
1062 		Main->priv->classes = g_hash_table_new_full (g_str_hash,
1063 							     g_str_equal,
1064 							     (GDestroyNotify) g_free,
1065 							     (GDestroyNotify) g_hash_table_destroy);
1066 		Main->priv->objects_order = g_hash_table_new_full (g_str_hash,
1067 							           g_str_equal,
1068 							           (GDestroyNotify) g_free,
1069 							           g_ptr_array_destroy);
1070 	}
1071 
1072 	superclass_name = g_type_name (superclass_type);
1073 	object_hash = g_hash_table_lookup (Main->priv->classes, superclass_name);
1074 	object_order = g_hash_table_lookup (Main->priv->objects_order, superclass_name);
1075 
1076 	if (object_hash == NULL) {
1077 		object_hash = g_hash_table_new_full (g_str_hash,
1078 						     g_str_equal,
1079 						     (GDestroyNotify) g_free,
1080 						     (GDestroyNotify) gth_type_spec_free);
1081 		g_hash_table_insert (Main->priv->classes, g_strdup (superclass_name), object_hash);
1082 
1083 		object_order = g_ptr_array_new ();
1084 		g_hash_table_insert (Main->priv->objects_order, g_strdup (superclass_name), object_order);
1085 	}
1086 
1087 	va_start (var_args, object_type);
1088 	spec = _gth_main_create_type_spec (object_type, var_args);
1089 	va_end (var_args);
1090 
1091 	id = g_strdup (object_id);
1092 	g_hash_table_insert (object_hash, id, spec);
1093 	g_ptr_array_add (object_order, id);
1094 
1095 	g_mutex_unlock (&register_mutex);
1096 }
1097 
1098 
1099 GList *
gth_main_get_registered_objects(GType superclass_type)1100 gth_main_get_registered_objects (GType superclass_type)
1101 {
1102 	GList      *objects = NULL;
1103 	GHashTable *object_hash;
1104 	GPtrArray  *object_order;
1105 	int         i;
1106 
1107 	object_hash = g_hash_table_lookup (Main->priv->classes, g_type_name (superclass_type));
1108 	if (object_hash == NULL)
1109 		return NULL;
1110 	object_order = g_hash_table_lookup (Main->priv->objects_order, g_type_name (superclass_type));
1111 
1112 	for (i = object_order->len - 1; i >= 0; i--) {
1113 		char        *object_id;
1114 		GthTypeSpec *spec;
1115 
1116 		object_id = g_ptr_array_index (object_order, i);
1117 		spec = g_hash_table_lookup (object_hash, object_id);
1118 		objects = g_list_prepend (objects, gth_type_spec_create_object (spec, object_id));
1119 	}
1120 
1121 	return objects;
1122 }
1123 
1124 
1125 GList *
gth_main_get_registered_objects_id(GType superclass_type)1126 gth_main_get_registered_objects_id (GType superclass_type)
1127 {
1128 	GList      *objects = NULL;
1129 	GHashTable *object_hash;
1130 	GPtrArray  *object_order;
1131 	int         i;
1132 
1133 	object_hash = g_hash_table_lookup (Main->priv->classes, g_type_name (superclass_type));
1134 	if (object_hash == NULL)
1135 		return NULL;
1136 	object_order = g_hash_table_lookup (Main->priv->objects_order, g_type_name (superclass_type));
1137 
1138 	for (i = object_order->len - 1; i >= 0; i--) {
1139 		char *object_id;
1140 
1141 		object_id = g_ptr_array_index (object_order, i);
1142 		objects = g_list_prepend (objects, g_strdup (object_id));
1143 	}
1144 
1145 	return objects;
1146 }
1147 
1148 
1149 gpointer
gth_main_get_registered_object(GType superclass_type,const char * object_id)1150 gth_main_get_registered_object (GType       superclass_type,
1151 				const char *object_id)
1152 {
1153 	GHashTable  *object_hash;
1154 	GthTypeSpec *spec;
1155 
1156 	object_hash = g_hash_table_lookup (Main->priv->classes, g_type_name (superclass_type));
1157 	if (object_hash == NULL)
1158 		return NULL;
1159 
1160 	spec = g_hash_table_lookup (object_hash, object_id);
1161 	if (spec == NULL)
1162 		return NULL;
1163 
1164 	return (gpointer) gth_type_spec_create_object (spec, object_id);
1165 }
1166 
1167 
1168 GBookmarkFile *
gth_main_get_default_bookmarks(void)1169 gth_main_get_default_bookmarks (void)
1170 {
1171 	GFile *file;
1172 	char  *filename;
1173 
1174 	if (Main->priv->bookmarks != NULL)
1175 		return Main->priv->bookmarks;
1176 
1177 	Main->priv->bookmarks = g_bookmark_file_new ();
1178 
1179 	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, BOOKMARKS_FILE, NULL);
1180 	filename = g_file_get_path (file);
1181 	g_bookmark_file_load_from_file (Main->priv->bookmarks, filename, NULL);
1182 
1183 	g_free (filename);
1184 	g_object_unref (file);
1185 
1186 	return Main->priv->bookmarks;
1187 }
1188 
1189 
1190 void
gth_main_bookmarks_changed(void)1191 gth_main_bookmarks_changed (void)
1192 {
1193 	GFile *file;
1194 	char  *filename;
1195 
1196 	file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, GTHUMB_DIR, BOOKMARKS_FILE, NULL);
1197 	filename = g_file_get_path (file);
1198 	g_bookmark_file_to_file (Main->priv->bookmarks, filename, NULL);
1199 
1200 	g_free (filename);
1201 	g_object_unref (file);
1202 
1203 	gth_monitor_bookmarks_changed (gth_main_get_default_monitor ());
1204 }
1205 
1206 
1207 void
gth_main_shortcuts_changed(GPtrArray * shortcuts_v)1208 gth_main_shortcuts_changed (GPtrArray *shortcuts_v)
1209 {
1210 	if (gth_shortcuts_write_to_file (shortcuts_v, NULL))
1211 		gth_monitor_shortcuts_changed (gth_main_get_default_monitor ());
1212 }
1213 
1214 
1215 GthFilterFile *
gth_main_get_default_filter_file(void)1216 gth_main_get_default_filter_file (void)
1217 {
1218 	GFile *file;
1219 
1220 	if (Main->priv->filters != NULL)
1221 		return Main->priv->filters;
1222 
1223 	Main->priv->filters = gth_filter_file_new ();
1224 	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, FILTERS_FILE, NULL);
1225 	gth_filter_file_load_from_file (Main->priv->filters, file, NULL);
1226 
1227 	g_object_unref (file);
1228 
1229 	return Main->priv->filters;
1230 }
1231 
1232 
1233 GList *
gth_main_get_all_filters(void)1234 gth_main_get_all_filters (void)
1235 {
1236 	GthFilterFile *filter_file;
1237 	GList         *filters;
1238 	GList         *registered_tests;
1239 	GList         *scan;
1240 	gboolean       changed = FALSE;
1241 
1242 	filter_file = gth_main_get_default_filter_file ();
1243 	filters = gth_filter_file_get_tests (filter_file);
1244 
1245 	registered_tests = gth_main_get_registered_objects_id (GTH_TYPE_TEST);
1246 	for (scan = registered_tests; scan; scan = scan->next) {
1247 		const char *registered_test_id = scan->data;
1248 		gboolean    test_present = FALSE;
1249 		GList      *scan2;
1250 
1251 		for (scan2 = filters; ! test_present && scan2; scan2 = scan2->next) {
1252 			GthTest *test = scan2->data;
1253 
1254 			if (g_strcmp0 (gth_test_get_id (test), registered_test_id) == 0)
1255 				test_present = TRUE;
1256 		}
1257 
1258 		if (! test_present) {
1259 			GthTest *registered_test;
1260 
1261 			registered_test = gth_main_get_registered_object (GTH_TYPE_TEST, registered_test_id);
1262 			filters = g_list_append (filters, registered_test);
1263 			gth_filter_file_add (filter_file, registered_test);
1264 			changed = TRUE;
1265 		}
1266 	}
1267 	_g_string_list_free (registered_tests);
1268 
1269 	if (changed)
1270 		gth_main_filters_changed ();
1271 
1272 	return filters;
1273 }
1274 
1275 
1276 void
gth_main_filters_changed(void)1277 gth_main_filters_changed (void)
1278 {
1279 	GFile *file;
1280 
1281 	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, FILTERS_FILE, NULL);
1282 	gth_filter_file_to_file (Main->priv->filters, file, NULL);
1283 	gth_monitor_filters_changed (gth_main_get_default_monitor ());
1284 
1285 	g_object_unref (file);
1286 }
1287 
1288 
1289 GthTagsFile *
gth_main_get_default_tag_file(void)1290 gth_main_get_default_tag_file (void)
1291 {
1292 	GFile *file;
1293 
1294 	if (Main->priv->tags != NULL)
1295 		return Main->priv->tags;
1296 
1297 	Main->priv->tags = gth_tags_file_new ();
1298 	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
1299 	gth_tags_file_load_from_file (Main->priv->tags, file, NULL);
1300 
1301 	g_object_unref (file);
1302 
1303 	return Main->priv->tags;
1304 }
1305 
1306 
1307 char **
gth_main_get_all_tags(void)1308 gth_main_get_all_tags (void)
1309 {
1310 	return gth_tags_file_get_tags (gth_main_get_default_tag_file ());
1311 }
1312 
1313 
1314 void
gth_main_tags_changed(void)1315 gth_main_tags_changed (void)
1316 {
1317 	GFile *file;
1318 
1319 	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
1320 	gth_tags_file_to_file (Main->priv->tags, file, NULL);
1321 	gth_monitor_tags_changed (gth_main_get_default_monitor ());
1322 
1323 	g_object_unref (file);
1324 }
1325 
1326 
1327 GthMonitor *
gth_main_get_default_monitor(void)1328 gth_main_get_default_monitor (void)
1329 {
1330 	if (G_LIKELY (Main->priv->monitor != NULL))
1331 		return Main->priv->monitor;
1332 
1333 	Main->priv->monitor = gth_monitor_new ();
1334 
1335 	return Main->priv->monitor;
1336 }
1337 
1338 
1339 GthExtensionManager *
gth_main_get_default_extension_manager(void)1340 gth_main_get_default_extension_manager (void)
1341 {
1342 	return Main->priv->extension_manager;
1343 }
1344 
1345 
1346 GthColorManager *
gth_main_get_default_color_manager(void)1347 gth_main_get_default_color_manager (void)
1348 {
1349 	if (Main->priv->color_manager == NULL)
1350 		Main->priv->color_manager = gth_color_manager_new ();
1351 	return Main->priv->color_manager;
1352 }
1353 
1354 
1355 void
gth_main_activate_extensions(void)1356 gth_main_activate_extensions (void)
1357 {
1358 	const char *mandatory_extensions[] = {
1359 		"file_viewer", /* keep the file viewer before any other viewer (see comment in gth-browser:file_metadata_ready_cb). */
1360 #ifdef HAVE_LIBJPEG
1361 		"jpeg_utils",  /* mandatory if jpeg support is activated at compile time */
1362 #endif
1363 		"cairo_io",
1364 		"image_viewer",
1365 		"file_tools",
1366 		NULL
1367 	};
1368 	const char *default_extensions[] = {
1369 		"23hq",
1370 		"bookmarks",
1371 		"burn_disc",
1372 		"catalogs",
1373 		"change_date",
1374 		"comments",
1375 		"contact_sheet",
1376 		"convert_format",
1377 		"desktop_background",
1378 		"edit_metadata",
1379 		"exiv2_tools",
1380 		"facebook",
1381 		"file_manager",
1382 		"find_duplicates",
1383 		"flicker",
1384 		"gstreamer_tools",
1385 		"gstreamer_utils",
1386 		"image_print",
1387 		"image_rotation",
1388 		"importer",
1389 		"jpeg_utils",
1390 		"list_tools",
1391 		"oauth",
1392 		"photo_importer",
1393 		"picasaweb",
1394 		"raw_files",
1395 		"red_eye_removal",
1396 		"rename_series",
1397 		"resize_images",
1398 		"search",
1399 		"selections",
1400 		"slideshow",
1401 		"terminal",
1402 		"webalbums",
1403 		NULL
1404 	};
1405 	GSettings            *settings;
1406 	char                **user_actived_extensions;
1407 	char                **actived_extensions;
1408 	GList                *ordered_extensions;
1409 	GthExtensionManager  *manager;
1410 	GList                *scan;
1411 
1412 	if (Main->priv->extension_manager == NULL)
1413 		Main->priv->extension_manager = gth_extension_manager_new ();
1414 
1415 	settings = g_settings_new (GTHUMB_GENERAL_SCHEMA);
1416 	user_actived_extensions = g_settings_get_strv (settings, PREF_GENERAL_ACTIVE_EXTENSIONS);
1417 	if ((user_actived_extensions != NULL)
1418 	     && (user_actived_extensions[1] == NULL)
1419 	     && (g_strcmp0 (user_actived_extensions[0], "default") == 0))
1420 	{
1421 		g_strfreev (user_actived_extensions);
1422 		user_actived_extensions = g_strdupv ((char **) default_extensions);
1423 		g_settings_set_strv (settings, PREF_GENERAL_ACTIVE_EXTENSIONS, (const char *const *) user_actived_extensions);
1424 	}
1425 	actived_extensions = _g_strv_concat ((char **) mandatory_extensions, user_actived_extensions);
1426 	ordered_extensions = gth_extension_manager_order_extensions (Main->priv->extension_manager, actived_extensions);
1427 
1428 	manager = gth_main_get_default_extension_manager ();
1429 	for (scan = ordered_extensions; scan; scan = scan->next) {
1430 		char                    *name = scan->data;
1431 		gboolean                 mandatory;
1432 		GthExtensionDescription *description;
1433 		GError                  *error = NULL;
1434 
1435 		mandatory = _g_strv_contains ((char **) mandatory_extensions, name);
1436 		description = gth_extension_manager_get_description (manager, name);
1437 		if (! mandatory && (description != NULL) && description->hidden)
1438 			continue;
1439 
1440 		if (! gth_extension_manager_activate (Main->priv->extension_manager, name, &error)) {
1441 			if (mandatory) {
1442 				g_critical ("Could not load the mandatory extension '%s': %s", name, error->message);
1443 				abort ();
1444 			}
1445 			else
1446 				g_warning ("Could not load the '%s' extension: %s", name, error->message);
1447 			g_clear_error (&error);
1448 		}
1449 	}
1450 
1451 	_g_string_list_free (ordered_extensions);
1452 	g_strfreev (actived_extensions);
1453 	g_strfreev (user_actived_extensions);
1454 }
1455 
1456 
1457 gboolean
gth_main_extension_is_active(const char * extension_name)1458 gth_main_extension_is_active (const char *extension_name)
1459 {
1460 	if (Main->priv->extension_manager == NULL)
1461 		return FALSE;
1462 	else
1463 		return gth_extension_manager_is_active (Main->priv->extension_manager, extension_name);
1464 }
1465 
1466 
1467 /* utilities */
1468 
1469 
1470 gboolean
attribute_list_reload_required(const char * old_attributes,const char * new_attributes)1471 attribute_list_reload_required (const char *old_attributes,
1472 				const char *new_attributes)
1473 {
1474 	char     **old_attributes_v;
1475 	char     **new_attributes_v;
1476 	int        new_attributes_len;
1477 	int        i;
1478 	gboolean   reload_required;
1479 
1480 	if (old_attributes == NULL)
1481 		return TRUE;
1482 
1483 	old_attributes_v = g_strsplit (old_attributes, ",", -1);
1484 	new_attributes_v = g_strsplit (new_attributes, ",", -1);
1485 	new_attributes_len = g_strv_length (new_attributes_v);
1486 
1487 	for (i = 0; i < new_attributes_len; i++) {
1488 		if (_g_utf8_all_spaces (new_attributes_v[i]) || _g_file_attributes_matches_any (new_attributes_v[i], GIO_ATTRIBUTES)) {
1489 			g_free (new_attributes_v[i]);
1490 			new_attributes_v[i] = NULL;
1491 		}
1492 	}
1493 
1494 	for (i = 0; (old_attributes_v[i] != NULL); i++) {
1495 		GthMetadataProvider *provider;
1496 		int                  j;
1497 
1498 		provider = gth_main_get_metadata_reader (old_attributes_v[i], "*");
1499 		if (provider == NULL)
1500 			continue;
1501 
1502 		for (j = 0; j < new_attributes_len; j++)
1503 			if ((new_attributes_v[j] != NULL)
1504 			    && (new_attributes_v[j][0] != '\0')
1505 			    && (strcmp (new_attributes_v[j], "none") != 0))
1506 			{
1507 				char *attr_v[2];
1508 
1509 				attr_v[0] = new_attributes_v[j];
1510 				attr_v[1] = NULL;
1511 				if (gth_metadata_provider_can_read (provider, "*", attr_v)) {
1512 					g_free (new_attributes_v[j]);
1513 					new_attributes_v[j] = NULL;
1514 				}
1515 			}
1516 
1517 		g_object_unref (provider);
1518 	}
1519 
1520 	/*
1521 	g_print ("old attributes: %s\n", old_attributes);
1522 	g_print ("new attributes: %s\n", new_attributes);
1523 	g_print ("attributes not available: \n");
1524 	*/
1525 
1526 	reload_required = FALSE;
1527 	for (i = 0; ! reload_required && (i < new_attributes_len); i++)
1528 		if ((new_attributes_v[i] != NULL)
1529 		    && (new_attributes_v[i][0] != '\0')
1530 		    && (strcmp (new_attributes_v[i], "none") != 0))
1531 		{
1532 			reload_required = TRUE;
1533 			/* g_print ("\t%s\n", new_attributes_v[i]); */
1534 		}
1535 
1536 	/* g_print ("reload required: %d\n", reload_required); */
1537 
1538 	g_strfreev (new_attributes_v);
1539 	g_strfreev (old_attributes_v);
1540 
1541 	return reload_required;
1542 }
1543