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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_mutex);
693 g_hash_table_insert (Main->priv->sort_types, (gpointer) sort_type->name, sort_type);
694 g_mutex_unlock (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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 (®ister_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