1 /* EasyTAG - Tag editor for audio files
2 * Copyright (C) 2014 David King <amigadave@amigadave.com>
3 * Copyright (C) 2000-2003 Jerome Couderc <easytag@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it 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 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <glib/gi18n.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29
30 #include "setting.h"
31 #include "application_window.h"
32 #include "cddb_dialog.h"
33 #include "load_files_dialog.h"
34 #include "playlist_dialog.h"
35 #include "preferences_dialog.h"
36 #include "search_dialog.h"
37 #include "easytag.h"
38 #include "charset.h"
39 #include "scan_dialog.h"
40 #include "log.h"
41 #include "misc.h"
42 #include "browser.h"
43 #include "et_core.h"
44
45 #include "win32/win32dep.h"
46
47 /* Referenced in the header. */
48 GSettings *MainSettings;
49
50 /***************
51 * Declaration *
52 ***************/
53
54 /*
55 * Nota :
56 * - no trailing slashes on directory name to avoid problem with
57 * NetBSD's mkdir(2).
58 */
59
60 // File of masks for tag scanner
61 static const gchar SCAN_TAG_MASKS_FILE[] = "scan_tag.mask";
62 // File of masks for rename file scanner
63 static const gchar RENAME_FILE_MASKS_FILE[] = "rename_file.mask";
64 // File for history of BrowserEntry combobox
65 static const gchar PATH_ENTRY_HISTORY_FILE[] = "browser_path.history";
66 // File for history of run program combobox for directories
67 static const gchar RUN_PROGRAM_WITH_DIRECTORY_HISTORY_FILE[] = "run_program_with_directory.history";
68 // File for history of run program combobox for files
69 static const gchar RUN_PROGRAM_WITH_FILE_HISTORY_FILE[] = "run_program_with_file.history";
70 // File for history of search string combobox
71 static const gchar SEARCH_FILE_HISTORY_FILE[] = "search_file.history";
72
73
74
75 /**************
76 * Prototypes *
77 **************/
78
79 static gboolean Create_Easytag_Directory (void);
80
81 /*************
82 * Functions *
83 *************/
84
85 static void
check_default_path(void)86 check_default_path (void)
87 {
88 GVariant *default_path;
89 const gchar *path;
90
91 default_path = g_settings_get_value (MainSettings, "default-path");
92 path = g_variant_get_bytestring (default_path);
93
94 if (!*path)
95 {
96 path = g_get_user_special_dir (G_USER_DIRECTORY_MUSIC);
97 g_settings_set_value (MainSettings, "default-path",
98 g_variant_new_bytestring (path ? path
99 : g_get_home_dir ()));
100 }
101
102 g_variant_unref (default_path);
103 }
104
105 /*
106 * Define and Load default values into config variables
107 */
Init_Config_Variables(void)108 void Init_Config_Variables (void)
109 {
110 MainSettings = g_settings_new ("org.gnome.EasyTAG");
111
112 /*
113 * Common
114 */
115 check_default_path ();
116 }
117
118 /*
119 * check_or_create_file:
120 * @filename: (type filename): the filename to create
121 *
122 * Check that the provided @filename exists, and if not, create it.
123 */
124 static void
check_or_create_file(const gchar * filename)125 check_or_create_file (const gchar *filename)
126 {
127 gchar *file_path;
128 GFile *file;
129 GFileOutputStream *ostream;
130 GError *error = NULL;
131
132 g_return_if_fail (filename != NULL);
133
134 file_path = g_build_filename (g_get_user_config_dir (), PACKAGE_TARNAME,
135 filename, NULL);
136
137 file = g_file_new_for_path (file_path);
138
139 if (!(ostream = g_file_append_to (file, G_FILE_CREATE_NONE, NULL, &error)))
140 {
141 g_debug ("Cannot create or open file ‘%s’: %s", file_path,
142 error->message);
143 g_error_free (error);
144 }
145 else
146 {
147 g_object_unref (ostream);
148 }
149
150 g_free (file_path);
151 g_object_unref (file);
152 }
153
154 /*
155 * Create the main directory with empty history files
156 */
Setting_Create_Files(void)157 gboolean Setting_Create_Files (void)
158 {
159 /* The file to write */
160 if (!Create_Easytag_Directory ())
161 {
162 return FALSE;
163 }
164
165 check_or_create_file (SCAN_TAG_MASKS_FILE);
166 check_or_create_file (RENAME_FILE_MASKS_FILE);
167 check_or_create_file (PATH_ENTRY_HISTORY_FILE);
168 check_or_create_file (RUN_PROGRAM_WITH_DIRECTORY_HISTORY_FILE);
169 check_or_create_file (RUN_PROGRAM_WITH_FILE_HISTORY_FILE);
170 check_or_create_file (SEARCH_FILE_HISTORY_FILE);
171
172 return TRUE;
173 }
174
175
176
177 /*
178 * Save the contents of a list store to a file
179 */
180 static void
Save_List_Store_To_File(const gchar * filename,GtkListStore * liststore,gint colnum)181 Save_List_Store_To_File (const gchar *filename,
182 GtkListStore *liststore,
183 gint colnum)
184 {
185 gchar *file_path;
186 gchar *display_path;
187 GFile *file;
188 GFileOutputStream *ostream;
189 GtkTreeIter iter;
190 GError *error = NULL;
191
192 if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter)
193 || !Create_Easytag_Directory ())
194 {
195 return;
196 }
197
198 /* The file to write */
199 file_path = g_build_filename (g_get_user_config_dir (), PACKAGE_TARNAME,
200 filename, NULL);
201 file = g_file_new_for_path (file_path);
202 g_free (file_path);
203
204 if (!(ostream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL,
205 &error)))
206 {
207 goto err;
208 }
209 else
210 {
211 GString *data;
212 gsize bytes_written;
213
214 data = g_string_new ("");
215
216 do
217 {
218 gchar *text;
219
220 gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, colnum,
221 &text, -1);
222 g_string_append (data, text);
223 g_free (text);
224 g_string_append_c (data, '\n');
225 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
226
227 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream), data->str,
228 data->len, &bytes_written, NULL,
229 &error))
230 {
231 g_string_free (data, TRUE);
232 g_object_unref (ostream);
233 goto err;
234 }
235
236 g_string_free (data, TRUE);
237 g_object_unref (ostream);
238 }
239
240 g_object_unref (file);
241 return;
242
243 err:
244 file_path = g_file_get_path (file);
245 display_path = g_filename_display_name (file_path);
246 Log_Print (LOG_ERROR, _("Cannot write list to file ‘%s’: %s"),
247 display_path, error->message);
248
249 g_error_free (error);
250 g_free (display_path);
251 g_free (file_path);
252 g_object_unref (file);
253 return;
254 }
255
256 /*
257 * Populate a list store with data from a file passed in as first parameter
258 */
259 static gboolean
Populate_List_Store_From_File(const gchar * filename,GtkListStore * liststore,gint text_column)260 Populate_List_Store_From_File (const gchar *filename,
261 GtkListStore *liststore,
262 gint text_column)
263 {
264 gchar *file_path;
265 GFile *file;
266 GFileInputStream *istream;
267 gboolean entries_set = FALSE;
268 GError *error = NULL;
269
270 /* The file to write */
271 g_return_val_if_fail (filename != NULL, FALSE);
272
273 file_path = g_build_filename (g_get_user_config_dir (), PACKAGE_TARNAME,
274 filename, NULL);
275 file = g_file_new_for_path (file_path);
276 g_free (file_path);
277
278 istream = g_file_read (file, NULL, &error);
279
280 if (!istream)
281 {
282 goto err;
283 }
284 else
285 {
286 GDataInputStream *data;
287 gsize bytes_read;
288 gchar *line;
289
290 data = g_data_input_stream_new (G_INPUT_STREAM (istream));
291 /* TODO: Find a safer alternative to _ANY. */
292 g_data_input_stream_set_newline_type (data,
293 G_DATA_STREAM_NEWLINE_TYPE_ANY);
294
295 while ((line = g_data_input_stream_read_line (data, &bytes_read, NULL,
296 &error)))
297 {
298 gchar *utf8_line;
299
300 utf8_line = Try_To_Validate_Utf8_String (line);
301 g_free (line);
302
303 if (!et_str_empty (utf8_line))
304 {
305 gtk_list_store_insert_with_values (liststore, NULL, G_MAXINT,
306 text_column, utf8_line, -1);
307 entries_set = TRUE;
308 }
309
310 g_free (utf8_line);
311 }
312
313 g_object_unref (data);
314
315 if (error)
316 {
317 g_object_unref (istream);
318 goto err;
319 }
320 }
321
322 g_object_unref (istream);
323 g_object_unref (file);
324
325 return entries_set;
326
327 err:
328 file_path = g_file_get_path (file);
329 Log_Print (LOG_ERROR, _("Cannot open file ‘%s’: %s"), file_path,
330 error->message);
331
332 g_free (file_path);
333 g_error_free (error);
334 g_object_unref (file);
335 return entries_set;
336 }
337
338
339 /*
340 * Functions for writing and reading list of 'Fill Tag' masks
341 */
342 void
Load_Scan_Tag_Masks_List(GtkListStore * liststore,gint colnum,const gchar * const * fallback)343 Load_Scan_Tag_Masks_List (GtkListStore *liststore, gint colnum,
344 const gchar * const *fallback)
345 {
346 gsize i = 0;
347 GtkTreeIter iter;
348
349 if (!Populate_List_Store_From_File(SCAN_TAG_MASKS_FILE, liststore, colnum))
350 {
351 /* Fall back to defaults. */
352 Log_Print (LOG_OK, _("Loading default ‘Fill Tag’ masks…"));
353
354 while(fallback[i])
355 {
356 gtk_list_store_insert_with_values (liststore, &iter, G_MAXINT,
357 colnum, fallback[i], -1);
358 i++;
359 }
360 }
361 }
362
Save_Scan_Tag_Masks_List(GtkListStore * liststore,gint colnum)363 void Save_Scan_Tag_Masks_List (GtkListStore *liststore, gint colnum)
364 {
365 Save_List_Store_To_File(SCAN_TAG_MASKS_FILE, liststore, colnum);
366 }
367
368
369 /*
370 * Functions for writing and reading list of 'Rename File' masks
371 */
372 void
Load_Rename_File_Masks_List(GtkListStore * liststore,gint colnum,const gchar * const * fallback)373 Load_Rename_File_Masks_List (GtkListStore *liststore, gint colnum,
374 const gchar * const *fallback)
375 {
376 gsize i = 0;
377 GtkTreeIter iter;
378
379 if (!Populate_List_Store_From_File(RENAME_FILE_MASKS_FILE, liststore, colnum))
380 {
381 /* Fall back to defaults. */
382 Log_Print (LOG_OK, _("Loading default ‘Rename File’ masks…"));
383
384 while(fallback[i])
385 {
386 gtk_list_store_insert_with_values (liststore, &iter, G_MAXINT,
387 colnum, fallback[i], -1);
388 i++;
389 }
390 }
391 }
392
Save_Rename_File_Masks_List(GtkListStore * liststore,gint colnum)393 void Save_Rename_File_Masks_List (GtkListStore *liststore, gint colnum)
394 {
395 Save_List_Store_To_File(RENAME_FILE_MASKS_FILE, liststore, colnum);
396 }
397
398 /*
399 * Functions for writing and reading list of 'BrowserEntry' combobox
400 */
Load_Path_Entry_List(GtkListStore * liststore,gint colnum)401 void Load_Path_Entry_List (GtkListStore *liststore, gint colnum)
402 {
403 Populate_List_Store_From_File(PATH_ENTRY_HISTORY_FILE, liststore, colnum);
404 }
Save_Path_Entry_List(GtkListStore * liststore,gint colnum)405 void Save_Path_Entry_List (GtkListStore *liststore, gint colnum)
406 {
407 Save_List_Store_To_File(PATH_ENTRY_HISTORY_FILE, liststore, colnum);
408 }
409
410 /*
411 * Functions for writing and reading list of combobox to run program (tree browser)
412 */
Load_Run_Program_With_Directory_List(GtkListStore * liststore,gint colnum)413 void Load_Run_Program_With_Directory_List (GtkListStore *liststore, gint colnum)
414 {
415 Populate_List_Store_From_File(RUN_PROGRAM_WITH_DIRECTORY_HISTORY_FILE, liststore, colnum);
416 }
Save_Run_Program_With_Directory_List(GtkListStore * liststore,gint colnum)417 void Save_Run_Program_With_Directory_List (GtkListStore *liststore, gint colnum)
418 {
419 Save_List_Store_To_File(RUN_PROGRAM_WITH_DIRECTORY_HISTORY_FILE, liststore, colnum);
420 }
421
422 /*
423 * Functions for writing and reading list of combobox to run program (file browser)
424 */
Load_Run_Program_With_File_List(GtkListStore * liststore,gint colnum)425 void Load_Run_Program_With_File_List (GtkListStore *liststore, gint colnum)
426 {
427 Populate_List_Store_From_File(RUN_PROGRAM_WITH_FILE_HISTORY_FILE, liststore, colnum);
428 }
Save_Run_Program_With_File_List(GtkListStore * liststore,gint colnum)429 void Save_Run_Program_With_File_List (GtkListStore *liststore, gint colnum)
430 {
431 Save_List_Store_To_File(RUN_PROGRAM_WITH_FILE_HISTORY_FILE, liststore, colnum);
432 }
433
434 /*
435 * Functions for writing and reading list of combobox to search a string into file (tag or filename)
436 */
Load_Search_File_List(GtkListStore * liststore,gint colnum)437 void Load_Search_File_List (GtkListStore *liststore, gint colnum)
438 {
439 Populate_List_Store_From_File(SEARCH_FILE_HISTORY_FILE, liststore, colnum);
440 }
Save_Search_File_List(GtkListStore * liststore,gint colnum)441 void Save_Search_File_List (GtkListStore *liststore, gint colnum)
442 {
443 Save_List_Store_To_File(SEARCH_FILE_HISTORY_FILE, liststore, colnum);
444 }
445
446 /*
447 * migrate_config_to_xdg_dir:
448 * @old_path: (type filename): the path to migrate from
449 * @new_path: (type filename): the path to migrate to
450 *
451 * Migrate the EasyTAG configuration files contained in the old path to the new
452 * one.
453 */
454 static void
migrate_config_file_dir(const gchar * old_path,const gchar * new_path)455 migrate_config_file_dir (const gchar *old_path, const gchar *new_path)
456 {
457 gsize i;
458 static const gchar *filenames[] = { SCAN_TAG_MASKS_FILE,
459 RENAME_FILE_MASKS_FILE,
460 PATH_ENTRY_HISTORY_FILE,
461 RUN_PROGRAM_WITH_DIRECTORY_HISTORY_FILE,
462 RUN_PROGRAM_WITH_FILE_HISTORY_FILE,
463 SEARCH_FILE_HISTORY_FILE,
464 NULL
465 };
466
467 g_debug ("Migrating configuration from directory ‘%s’ to ‘%s’", old_path,
468 new_path);
469
470 for (i = 0; filenames[i]; i++)
471 {
472 gchar *old_filename, *new_filename;
473 GFile *old_file, *new_file;
474
475 old_filename = g_build_filename (old_path, filenames[i], NULL);
476
477 if (!g_file_test (old_filename, G_FILE_TEST_EXISTS))
478 {
479 g_free (old_filename);
480 continue;
481 }
482
483 new_filename = g_build_filename (new_path, filenames[i], NULL);
484 old_file = g_file_new_for_path (old_filename);
485 new_file = g_file_new_for_path (new_filename);
486
487 if (!g_file_move (old_file, new_file, G_FILE_COPY_NONE, NULL, NULL,
488 NULL, NULL))
489 {
490 g_debug ("Failed to migrate configuration file ‘%s’",
491 filenames[i]);
492 }
493
494 g_free (old_filename);
495 g_free (new_filename);
496 g_object_unref (old_file);
497 g_object_unref (new_file);
498 }
499 }
500
501 /**
502 * Create the directory used by EasyTAG to store user configuration files.
503 *
504 * Returns: %TRUE if the directory was created, or already exists. %FALSE if
505 * the directory could not be created.
506 */
507 static gboolean
Create_Easytag_Directory(void)508 Create_Easytag_Directory (void)
509 {
510 gchar *easytag_path = NULL;
511 gint result;
512
513 /* Directory to create (if it does not exist) with absolute path. */
514 easytag_path = g_build_filename (g_get_user_config_dir (), PACKAGE_TARNAME,
515 NULL);
516
517 if (g_file_test (easytag_path, G_FILE_TEST_IS_DIR))
518 {
519 g_free (easytag_path);
520 return TRUE;
521 }
522
523 result = g_mkdir_with_parents (easytag_path, S_IRWXU);
524
525 if (result == -1)
526 {
527 g_debug ("Cannot create directory ‘%s’: %s", easytag_path,
528 g_strerror (errno));
529 g_free (easytag_path);
530 return FALSE;
531 }
532 else
533 {
534 gchar *old_path = g_build_filename (g_get_home_dir (),
535 "." PACKAGE_TARNAME, NULL);
536
537 if (g_file_test (old_path, G_FILE_TEST_IS_DIR))
538 {
539 migrate_config_file_dir (old_path, easytag_path);
540 }
541
542 g_free (old_path);
543 g_free (easytag_path);
544
545 return TRUE;
546 }
547 }
548
549 /*
550 * et_settings_enum_get:
551 * @value: the property value to be set (active item on combo box)
552 * @variant: the variant to set the @value from
553 * @user_data: the #GType of the #GSettings enum
554 *
555 * Wrapper function to convert an enum-type GSettings key into an integer
556 * value.
557 *
558 * Returns: %TRUE if the mapping was successful, %FALSE otherwise
559 */
560 gboolean
et_settings_enum_get(GValue * value,GVariant * variant,gpointer user_data)561 et_settings_enum_get (GValue *value, GVariant *variant, gpointer user_data)
562 {
563 GType enum_type;
564 GEnumClass *enum_class;
565 GEnumValue *enum_value;
566 const gchar *nick;
567
568 g_return_val_if_fail (user_data != NULL, FALSE);
569
570 enum_type = (GType)GPOINTER_TO_SIZE (user_data);
571 enum_class = g_type_class_ref (enum_type);
572 nick = g_variant_get_string (variant, NULL);
573 enum_value = g_enum_get_value_by_nick (enum_class, nick);
574 g_type_class_unref (enum_class);
575
576 if (!enum_value)
577 {
578 g_warning ("Unable to lookup %s enum nick '%s' from GType",
579 g_type_name (enum_type),
580 nick);
581 return FALSE;
582 }
583
584 g_value_set_int (value, enum_value->value);
585 return TRUE;
586 }
587
588 /*
589 * et_settings_enum_set:
590 * @value: the property value to set the @variant from
591 * @expected_type: the expected type of the returned variant
592 * @user_data: the #GType of the #GSettings enum
593 *
594 * Wrapper function to convert an integer value into a string suitable for
595 * storing into an enum-type GSettings key.
596 *
597 * Returns: a new GVariant containing the mapped value, or %NULL upon failure
598 */
599 GVariant *
et_settings_enum_set(const GValue * value,const GVariantType * expected_type,gpointer user_data)600 et_settings_enum_set (const GValue *value, const GVariantType *expected_type,
601 gpointer user_data)
602 {
603 GType enum_type;
604 GEnumClass *enum_class;
605 GEnumValue *enum_value;
606
607 g_return_val_if_fail (user_data != NULL, NULL);
608
609 enum_type = (GType)GPOINTER_TO_SIZE (user_data);
610 enum_class = g_type_class_ref (enum_type);
611 enum_value = g_enum_get_value (enum_class, g_value_get_int (value));
612 g_type_class_unref (enum_class);
613
614 if (!enum_value)
615 {
616 g_warning ("Unable to lookup %s enum value '%d' from GType",
617 g_type_name (enum_type), g_value_get_int (value));
618 return NULL;
619 }
620
621 return g_variant_new (g_variant_type_peek_string (expected_type),
622 enum_value->value_nick);
623 }
624
625 /*
626 * et_settings_enum_radio_get:
627 * @value: the property value to be set
628 * @variant: the variant to set the @value from
629 * @user_data: the widget on which the setting should be applied
630 *
631 * Wrapper function to convert an enum-type GSettings key state to the active
632 * radio button.
633 *
634 * Returns: %TRUE
635 */
636 gboolean
et_settings_enum_radio_get(GValue * value,GVariant * variant,gpointer user_data)637 et_settings_enum_radio_get (GValue *value, GVariant *variant,
638 gpointer user_data)
639 {
640 const gchar *name;
641 const gchar *setting;
642
643 name = gtk_widget_get_name (GTK_WIDGET (user_data));
644 setting = g_variant_get_string (variant, NULL);
645
646 /* Only set the radio button which matches the setting to active. */
647 if (g_strcmp0 (name, setting) == 0)
648 {
649 g_value_set_boolean (value, TRUE);
650 }
651
652 return TRUE;
653 }
654
655 /*
656 * et_settings_enum_radio_set:
657 * @value: the property value to set the @variant from
658 * @expected_type: the expected type of the returned variant
659 * @user_data: the widget which the setting should be taken from
660 *
661 * Wrapper function to convert the active radiobutton to the value of an
662 * enum-type GSettings key.
663 *
664 * Returns: a new GVariant containing the mapped value, or %NULL upon failure
665 */
666 GVariant *
et_settings_enum_radio_set(const GValue * value,const GVariantType * expected_type,gpointer user_data)667 et_settings_enum_radio_set (const GValue *value,
668 const GVariantType *expected_type,
669 gpointer user_data)
670 {
671 GVariant *variant = NULL;
672 const gchar *name;
673
674 /* Ignore buttons that are not active. */
675 if (!g_value_get_boolean (value))
676 {
677 return variant;
678 }
679
680 name = gtk_widget_get_name (GTK_WIDGET (user_data));
681 variant = g_variant_new_string (name);
682
683 return variant;
684 }
685
686 /*
687 * et_settings_flags_toggle_get:
688 * @value: the property value to be set (active item on combo box)
689 * @variant: the variant to set the @value from
690 * @user_data: the #GType of the #GSettings flags
691 *
692 * Wrapper function to convert a flags-type GSettings key state into the active
693 * toggle button.
694 *
695 * Returns: %TRUE if the mapping was successful, %FALSE otherwise
696 */
697 gboolean
et_settings_flags_toggle_get(GValue * value,GVariant * variant,gpointer user_data)698 et_settings_flags_toggle_get (GValue *value, GVariant *variant, gpointer user_data)
699 {
700 const gchar *name;
701 GType flags_type;
702 GFlagsClass *flags_class;
703 GVariantIter iter;
704 GFlagsValue *flags_value;
705 const gchar *nick;
706 guint flags = 0;
707
708 g_return_val_if_fail (user_data != NULL, FALSE);
709
710 name = gtk_widget_get_name (GTK_WIDGET (user_data));
711 flags_type = (GType)GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (user_data),
712 "flags-type"));
713 flags_class = g_type_class_ref (flags_type);
714
715 g_variant_iter_init (&iter, variant);
716
717 while (g_variant_iter_next (&iter, "&s", &nick))
718 {
719 flags_value = g_flags_get_value_by_nick (flags_class, nick);
720
721 if (flags_value)
722 {
723 flags |= flags_value->value;
724 }
725 else
726 {
727 g_warning ("Unable to lookup %s flags nick '%s' from GType",
728 g_type_name (flags_type), nick);
729 g_type_class_unref (flags_class);
730 return FALSE;
731 }
732 }
733
734 flags_value = g_flags_get_value_by_nick (flags_class, name);
735 g_type_class_unref (flags_class);
736
737 /* TRUE if settings flag is set for this widget, which will make the widget
738 * active. */
739 g_value_set_boolean (value, flags & flags_value->value);
740 return TRUE;
741 }
742
743 /*
744 * et_settings_flags_toggle_set:
745 * @value: the property value to set the @variant from
746 * @expected_type: the expected type of the returned variant
747 * @user_data: the widget associated with the changed setting
748 *
749 * Wrapper function to convert a boolean value into a string suitable for
750 * storing into a flags-type GSettings key.
751 *
752 * Returns: a new GVariant containing the mapped value, or %NULL upon failure
753 */
754 GVariant *
et_settings_flags_toggle_set(const GValue * value,const GVariantType * expected_type,gpointer user_data)755 et_settings_flags_toggle_set (const GValue *value,
756 const GVariantType *expected_type,
757 gpointer user_data)
758 {
759 const gchar *name;
760 GType flags_type;
761 GFlagsClass *flags_class;
762 GFlagsValue *flags_value;
763 guint mask;
764 GVariantBuilder builder;
765 const gchar *flags_key;
766 guint flags;
767
768 g_return_val_if_fail (user_data != NULL, NULL);
769
770 name = gtk_widget_get_name (GTK_WIDGET (user_data));
771 flags_type = (GType)GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (user_data),
772 "flags-type"));
773 flags_class = g_type_class_ref (flags_type);
774 flags_value = g_flags_get_value_by_nick (flags_class, name);
775 mask = flags_class->mask;
776
777 if (!flags_value)
778 {
779 g_warning ("Unable to lookup %s flags value '%d' from GType",
780 g_type_name (flags_type), g_value_get_boolean (value));
781 g_type_class_unref (flags_class);
782 return NULL;
783 }
784
785 flags_key = g_object_get_data (G_OBJECT (user_data), "flags-key");
786 flags = g_settings_get_flags (MainSettings, flags_key);
787
788 if (g_value_get_boolean (value))
789 {
790 flags |= flags_value->value;
791 }
792 else
793 {
794 flags &= (flags_value->value ^ mask);
795 }
796
797 g_variant_builder_init (&builder, expected_type);
798
799 while (flags)
800 {
801 flags_value = g_flags_get_first_value (flags_class, flags);
802
803 if (flags_value == NULL)
804 {
805 g_variant_builder_clear (&builder);
806 g_type_class_unref (flags_class);
807 return NULL;
808 }
809
810 g_variant_builder_add (&builder, "s", flags_value->value_nick);
811 flags &= ~flags_value->value;
812 }
813
814 g_type_class_unref (flags_class);
815
816 return g_variant_builder_end (&builder);
817 }
818