geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

stash.c
Go to the documentation of this file.
1/*
2 * stash.c - this file is part of Geany, a fast and lightweight IDE
3 *
4 * Copyright 2008 The Geany contributors
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/**
22 * @file stash.h
23 * Lightweight library for reading/writing @c GKeyFile settings and synchronizing widgets with
24 * C variables.
25 *
26 * Note: Stash should only depend on GLib and GTK, but currently has some minor
27 * dependencies on Geany's utils.c.
28 *
29 * @section Terms
30 * 'Setting' is used only for data stored on disk or in memory.
31 * 'Pref' can also include visual widget information.
32 *
33 * @section Memory Usage
34 * Stash will not duplicate strings if they are normally static arrays, such as
35 * keyfile group names and key names, string default values, widget_id names, property names.
36 *
37 * @section String Settings
38 * String settings and other dynamically allocated settings will be initialized to NULL when
39 * added to a StashGroup (so they can safely be reassigned later).
40 *
41 * @section Widget Support
42 * Widgets very commonly used in configuration dialogs will be supported with their own function.
43 * Widgets less commonly used such as @c GtkExpander or widget settings that aren't commonly needed
44 * to be persistent won't be directly supported, to keep the library lightweight. However, you can
45 * use stash_group_add_widget_property() to also save these settings for any read/write widget
46 * property. Macros could be added for common widget properties such as @c GtkExpander:"expanded".
47 *
48 * @section settings-example Settings Example
49 * Here we have some settings for how to make a cup - whether it should be made of china
50 * and who's going to make it. (Yes, it's a stupid example).
51 * @include stash-example.c
52 * @note You might want to handle the warning/error conditions differently from above.
53 *
54 * @section prefs-example GUI Prefs Example
55 * For prefs, it's the same as the above example but you tell Stash to add widget prefs instead of
56 * just data settings.
57 *
58 * This example uses lookup strings for widgets as they are more flexible than widget pointers.
59 * Code to load and save the settings is omitted - see the first example instead.
60 *
61 * Here we show a dialog with a toggle button for whether the cup should have a handle.
62 * @include stash-gui-example.c
63 * @note This example should also work for other widget containers besides dialogs, e.g. popup menus.
64 */
65
66/* Implementation Note
67 * We dynamically allocate prefs. It would be more efficient for user code to declare
68 * a static array of StashPref structs, but we don't do this because:
69 *
70 * * It would be more ugly (lots of casts and NULLs).
71 * * Less type checking.
72 * * The API & ABI would have to break when adding/changing fields.
73 *
74 * Usually the prefs code isn't what user code will spend most of its time doing, so this
75 * should be efficient enough.
76 */
77
78#include "stash.h"
79
80#include "support.h" /* only for _("text") */
81#include "utils.h" /* only for foreach_*, utils_get_setting_*(). Stash should not depend on Geany. */
82
83#include <stdlib.h> /* only for atoi() */
84
85
86/* GTK3 removed ComboBoxEntry, but we need a value to differentiate combo box with and
87 * without entries, and it must not collide with other GTypes */
88#define TYPE_COMBO_BOX_ENTRY get_combo_box_entry_type()
89static GType get_combo_box_entry_type(void)
90{
91 static volatile gsize type = 0;
92 if (g_once_init_enter(&type))
93 {
94 GType g_type = g_type_register_static_simple(GTK_TYPE_COMBO_BOX, "dummy-combo-box-entry",
95 sizeof(GtkComboBoxClass), NULL, sizeof(GtkComboBox), NULL, G_TYPE_FLAG_ABSTRACT);
96 g_once_init_leave(&type, g_type);
97 }
98 return type;
99}
100
101
103{
104 GType setting_type; /* e.g. G_TYPE_INT */
105 gpointer setting; /* Address of a variable */
106 const gchar *key_name;
107 gpointer default_value; /* Default value, e.g. (gpointer)1 */
108 GType widget_type; /* e.g. GTK_TYPE_TOGGLE_BUTTON */
109 StashWidgetID widget_id; /* (GtkWidget*) or (gchar*) */
110 union
111 {
113 const gchar *property_name;
114 } extra; /* extra fields depending on widget_type */
115};
116
117typedef struct StashPref StashPref;
118
120{
121 guint refcount; /* ref count for GBoxed implementation */
122 const gchar *name; /* group name to use in the keyfile */
123 GPtrArray *entries; /* array of (StashPref*) */
124 gboolean various; /* mark group for display/edit in stash treeview */
125 const gchar *prefix; /* text to display for Various UI instead of name */
126 gboolean use_defaults; /* use default values if there's no keyfile entry */
127};
128
129typedef struct EnumWidget
130{
133}
135
136
137typedef enum SettingAction
138{
143
144typedef enum PrefAction
145{
150
151
153 GKeyFile *config, SettingAction action)
154{
155 gboolean *setting = se->setting;
156
157 switch (action)
158 {
159 case SETTING_READ:
160 *setting = utils_get_setting_boolean(config, group->name, se->key_name,
161 GPOINTER_TO_INT(se->default_value));
162 break;
163 case SETTING_WRITE:
164 g_key_file_set_boolean(config, group->name, se->key_name, *setting);
165 break;
166 }
167}
168
169
171 GKeyFile *config, SettingAction action)
172{
173 gint *setting = se->setting;
174
175 switch (action)
176 {
177 case SETTING_READ:
178 *setting = utils_get_setting_integer(config, group->name, se->key_name,
179 GPOINTER_TO_INT(se->default_value));
180 break;
181 case SETTING_WRITE:
182 g_key_file_set_integer(config, group->name, se->key_name, *setting);
183 break;
184 }
185}
186
187
189 GKeyFile *config, SettingAction action)
190{
191 gchararray *setting = se->setting;
192
193 switch (action)
194 {
195 case SETTING_READ:
196 g_free(*setting);
197 *setting = utils_get_setting_string(config, group->name, se->key_name,
198 se->default_value);
199 break;
200 case SETTING_WRITE:
201 g_key_file_set_string(config, group->name, se->key_name,
202 *setting ? *setting : "");
203 break;
204 }
205}
206
207
209 GKeyFile *config, SettingAction action)
210{
211 gchararray **setting = se->setting;
212
213 switch (action)
214 {
215 case SETTING_READ:
216 g_strfreev(*setting);
217 *setting = g_key_file_get_string_list(config, group->name, se->key_name,
218 NULL, NULL);
219 if (*setting == NULL)
220 *setting = g_strdupv(se->default_value);
221 break;
222
223 case SETTING_WRITE:
224 {
225 /* don't try to save a NULL string vector */
226 const gchar *dummy[] = { "", NULL };
227 const gchar **strv = *setting ? (const gchar **)*setting : dummy;
228
229 g_key_file_set_string_list(config, group->name, se->key_name,
230 strv, g_strv_length((gchar **)strv));
231 break;
232 }
233 }
234}
235
236
237static void keyfile_action(SettingAction action, StashGroup *group, GKeyFile *keyfile)
238{
240 guint i;
241
243 {
244 /* don't override settings with default values */
245 if (!group->use_defaults && action == SETTING_READ &&
246 !g_key_file_has_key(keyfile, group->name, entry->key_name, NULL))
247 continue;
248
249 switch (entry->setting_type)
250 {
251 case G_TYPE_BOOLEAN:
252 handle_boolean_setting(group, entry, keyfile, action); break;
253 case G_TYPE_INT:
254 handle_integer_setting(group, entry, keyfile, action); break;
255 case G_TYPE_STRING:
256 handle_string_setting(group, entry, keyfile, action); break;
257 default:
258 /* Note: G_TYPE_STRV is not a constant, can't use case label */
259 if (entry->setting_type == G_TYPE_STRV)
260 handle_strv_setting(group, entry, keyfile, action);
261 else
262 g_warning("Unhandled type for %s::%s in %s()!", group->name, entry->key_name,
263 G_STRFUNC);
264 }
265 }
266}
267
268
269/** Reads key values from @a keyfile into the group settings.
270 * @note You should still call this even if the keyfile couldn't be loaded from disk
271 * so that all Stash settings are initialized to defaults.
272 * @param group .
273 * @param keyfile Usually loaded from a configuration file first. */
274GEANY_API_SYMBOL
276{
278}
279
280
281/** Writes group settings into key values in @a keyfile.
282 * @a keyfile is usually written to a configuration file afterwards.
283 * @param group .
284 * @param keyfile . */
285GEANY_API_SYMBOL
287{
289}
290
291
292/** Reads group settings from a configuration file using @c GKeyFile.
293 * @note Stash settings will be initialized to defaults if the keyfile
294 * couldn't be loaded from disk.
295 * @param group .
296 * @param filename Filename of the file to read, in locale encoding.
297 * @return @c TRUE if a key file could be loaded.
298 * @see stash_group_load_from_key_file().
299 **/
300GEANY_API_SYMBOL
302{
303 GKeyFile *keyfile;
304 gboolean ret;
305
306 keyfile = g_key_file_new();
307 ret = g_key_file_load_from_file(keyfile, filename, 0, NULL);
308 /* even on failure we load settings to apply defaults */
310
311 g_key_file_free(keyfile);
312 return ret;
313}
314
315
316/** Writes group settings to a configuration file using @c GKeyFile.
317 *
318 * @param group .
319 * @param filename Filename of the file to write, in locale encoding.
320 * @param flags Keyfile options - @c G_KEY_FILE_NONE is the most efficient.
321 * @return 0 if the file was successfully written, otherwise the @c errno of the
322 * failed operation is returned.
323 * @see stash_group_save_to_key_file().
324 **/
325GEANY_API_SYMBOL
327 GKeyFileFlags flags)
328{
329 GKeyFile *keyfile;
330 gchar *data;
331 gint ret;
332
333 keyfile = g_key_file_new();
334 /* if we need to keep comments or translations, try to load first */
335 if (flags)
336 g_key_file_load_from_file(keyfile, filename, flags, NULL);
337
339 data = g_key_file_to_data(keyfile, NULL, NULL);
340 ret = utils_write_file(filename, data);
341 g_free(data);
342 g_key_file_free(keyfile);
343 return ret;
344}
345
346
347static void free_stash_pref(StashPref *pref)
348{
349 if (pref->widget_type == GTK_TYPE_RADIO_BUTTON)
350 g_free(pref->extra.radio_buttons);
351
352 g_slice_free(StashPref, pref);
353}
354
355
356/** Creates a new group.
357 * @param name Name used for @c GKeyFile group.
358 * @return Group. */
359GEANY_API_SYMBOL
361{
362 StashGroup *group = g_slice_new0(StashGroup);
363
364 group->name = name;
365 group->entries = g_ptr_array_new_with_free_func((GDestroyNotify) free_stash_pref);
366 group->use_defaults = TRUE;
367 group->refcount = 1;
368 return group;
369}
370
371
372/** Frees the memory allocated for setting values in a group.
373 * Useful e.g. to avoid freeing strings individually.
374 * @note This is *not* called by stash_group_free().
375 * @param group . */
376GEANY_API_SYMBOL
378{
380 guint i;
381
383 {
384 if (entry->setting_type == G_TYPE_STRING)
385 g_free(*(gchararray *) entry->setting);
386 else if (entry->setting_type == G_TYPE_STRV)
387 g_strfreev(*(gchararray **) entry->setting);
388 else
389 continue;
390
391 *(gpointer**) entry->setting = NULL;
392 }
393}
394
395
397{
398 g_atomic_int_inc(&src->refcount);
399
400 return src;
401}
402
403
404/** Frees a group.
405 * @param group . */
406GEANY_API_SYMBOL
408{
409 if (g_atomic_int_dec_and_test(&group->refcount))
410 {
411 g_ptr_array_free(group->entries, TRUE);
412 g_slice_free(StashGroup, group);
413 }
414}
415
416
417/** Gets the GBoxed-derived GType for StashGroup
418 *
419 * @return StashGroup type . */
420GEANY_API_SYMBOL
422
424
425
426/* Used for selecting groups passed to stash_tree_setup().
427 * @param various @c FALSE by default.
428 * @param prefix @nullable Group prefix or @c NULL to use @c group->name. */
430 const gchar *prefix)
431{
432 group->various = various;
433 group->prefix = prefix;
434}
435
436
437/* When @c FALSE, Stash doesn't change the setting if there is no keyfile entry, so it
438 * remains whatever it was initialized/set to by user code.
439 * @c TRUE by default. */
440void stash_group_set_use_defaults(StashGroup *group, gboolean use_defaults)
441{
442 group->use_defaults = use_defaults;
443}
444
445
446static StashPref *
447add_pref(StashGroup *group, GType type, gpointer setting,
448 const gchar *key_name, gpointer default_value)
449{
450 StashPref init = {type, setting, key_name, default_value, G_TYPE_NONE, NULL, {NULL}};
451 StashPref *entry = g_slice_new(StashPref);
452
453 *entry = init;
454
455 /* init any pointer settings to NULL so they can be freed later */
456 if (type == G_TYPE_STRING ||
457 type == G_TYPE_STRV)
458 if (group->use_defaults)
459 *(gpointer**)setting = NULL;
460
461 g_ptr_array_add(group->entries, entry);
462 return entry;
463}
464
465
466/** Adds boolean setting.
467 * @param group .
468 * @param setting Address of setting variable.
469 * @param key_name Name for key in a @c GKeyFile.
470 * @param default_value Value to use if the key doesn't exist when loading. */
471GEANY_API_SYMBOL
472void stash_group_add_boolean(StashGroup *group, gboolean *setting,
473 const gchar *key_name, gboolean default_value)
474{
475 add_pref(group, G_TYPE_BOOLEAN, setting, key_name, GINT_TO_POINTER(default_value));
476}
477
478
479/** Adds integer setting.
480 * @param group .
481 * @param setting Address of setting variable.
482 * @param key_name Name for key in a @c GKeyFile.
483 * @param default_value Value to use if the key doesn't exist when loading. */
484GEANY_API_SYMBOL
486 const gchar *key_name, gint default_value)
487{
488 add_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value));
489}
490
491
492/** Adds string setting.
493 * The contents of @a setting will be initialized to @c NULL.
494 * @param group .
495 * @param setting Address of setting variable.
496 * @param key_name Name for key in a @c GKeyFile.
497 * @param default_value @nullable String to copy if the key doesn't exist when loading, or @c NULL. */
498GEANY_API_SYMBOL
500 const gchar *key_name, const gchar *default_value)
501{
502 add_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value);
503}
504
505
506/** Adds string vector setting (array of strings).
507 * The contents of @a setting will be initialized to @c NULL.
508 * @param group .
509 * @param setting Address of setting variable.
510 * @param key_name Name for key in a @c GKeyFile.
511 * @param default_value Vector to copy if the key doesn't exist when loading. Usually @c NULL. */
512GEANY_API_SYMBOL
514 const gchar *key_name, const gchar **default_value)
515{
516 add_pref(group, G_TYPE_STRV, setting, key_name, (gpointer)default_value);
517}
518
519
520/* *** GTK-related functions *** */
521
522static void handle_toggle_button(GtkWidget *widget, gboolean *setting,
523 PrefAction action)
524{
525 switch (action)
526 {
527 case PREF_DISPLAY:
528 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *setting);
529 break;
530 case PREF_UPDATE:
531 *setting = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
532 break;
533 }
534}
535
536
537static void handle_spin_button(GtkWidget *widget, StashPref *entry,
538 PrefAction action)
539{
540 gint *setting = entry->setting;
541
542 g_assert(entry->setting_type == G_TYPE_INT); /* only int spin prefs */
543
544 switch (action)
545 {
546 case PREF_DISPLAY:
547 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), *setting);
548 break;
549 case PREF_UPDATE:
550 /* if the widget is focussed, the value might not be updated */
551 gtk_spin_button_update(GTK_SPIN_BUTTON(widget));
552 *setting = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
553 break;
554 }
555}
556
557
558static void handle_combo_box(GtkWidget *widget, StashPref *entry,
559 PrefAction action)
560{
561 gint *setting = entry->setting;
562
563 switch (action)
564 {
565 case PREF_DISPLAY:
566 gtk_combo_box_set_active(GTK_COMBO_BOX(widget), *setting);
567 break;
568 case PREF_UPDATE:
569 *setting = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
570 break;
571 }
572}
573
574
575static void handle_entry(GtkWidget *widget, StashPref *entry,
576 PrefAction action)
577{
578 gchararray *setting = entry->setting;
579
580 switch (action)
581 {
582 case PREF_DISPLAY:
583 gtk_entry_set_text(GTK_ENTRY(widget), *setting);
584 break;
585 case PREF_UPDATE:
586 g_free(*setting);
587 *setting = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
588 break;
589 }
590}
591
592
593static void handle_combo_box_entry(GtkWidget *widget, StashPref *entry,
594 PrefAction action)
595{
596 widget = gtk_bin_get_child(GTK_BIN(widget));
597 handle_entry(widget, entry, action);
598}
599
600
601/* taken from Glade 2.x generated support.c */
602static GtkWidget*
603lookup_widget(GtkWidget *widget, const gchar *widget_name)
604{
605 GtkWidget *parent, *found_widget;
606
607 g_return_val_if_fail(widget != NULL, NULL);
608 g_return_val_if_fail(widget_name != NULL, NULL);
609
610 for (;;)
611 {
612 if (GTK_IS_MENU(widget))
613 parent = gtk_menu_get_attach_widget(GTK_MENU(widget));
614 else
615 parent = gtk_widget_get_parent(widget);
616 if (parent == NULL)
617 parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey");
618 if (parent == NULL)
619 break;
620 widget = parent;
621 }
622
623 found_widget = (GtkWidget*) g_object_get_data(G_OBJECT(widget), widget_name);
624 if (G_UNLIKELY(found_widget == NULL))
625 g_warning("Widget not found: %s", widget_name);
626 return found_widget;
627}
628
629
630static GtkWidget *
631get_widget(GtkWidget *owner, StashWidgetID widget_id)
632{
633 GtkWidget *widget;
634
635 if (owner)
636 widget = lookup_widget(owner, (const gchar *)widget_id);
637 else
638 widget = (GtkWidget *)widget_id;
639
640 if (!GTK_IS_WIDGET(widget))
641 {
642 g_warning("Unknown widget in %s()!", G_STRFUNC);
643 return NULL;
644 }
645 return widget;
646}
647
648
649static void handle_radio_button(GtkWidget *widget, gint enum_id, gboolean *setting,
650 PrefAction action)
651{
652 switch (action)
653 {
654 case PREF_DISPLAY:
655 if (*setting == enum_id)
656 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
657 break;
658 case PREF_UPDATE:
659 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
660 *setting = enum_id;
661 break;
662 }
663}
664
665
666static void handle_radio_buttons(GtkWidget *owner, StashPref *entry,
667 PrefAction action)
668{
669 EnumWidget *field = entry->extra.radio_buttons;
670 gsize count = 0;
671 GtkWidget *widget = NULL;
672
673 while (1)
674 {
675 widget = get_widget(owner, field->widget_id);
676
677 if (!widget)
678 continue;
679
680 count++;
681 handle_radio_button(widget, field->enum_id, entry->setting, action);
682 field++;
683 if (!field->widget_id)
684 break;
685 }
686 if (g_slist_length(gtk_radio_button_get_group(GTK_RADIO_BUTTON(widget))) != count)
687 g_warning("Missing/invalid radio button widget IDs found!");
688}
689
690
691static void handle_widget_property(GtkWidget *widget, StashPref *entry,
692 PrefAction action)
693{
694 GObject *object = G_OBJECT(widget);
695 const gchar *name = entry->extra.property_name;
696
697 switch (action)
698 {
699 case PREF_DISPLAY:
700 if (entry->setting_type == G_TYPE_BOOLEAN)
701 g_object_set(object, name, *(gboolean*)entry->setting, NULL);
702 else if (entry->setting_type == G_TYPE_INT)
703 g_object_set(object, name, *(gint*)entry->setting, NULL);
704 else if (entry->setting_type == G_TYPE_STRING)
705 g_object_set(object, name, *(gchararray*)entry->setting, NULL);
706 else if (entry->setting_type == G_TYPE_STRV)
707 g_object_set(object, name, *(gchararray**)entry->setting, NULL);
708 else
709 {
710 g_warning("Unhandled type %s for %s in %s()!", g_type_name(entry->setting_type),
711 entry->key_name, G_STRFUNC);
712 }
713 break;
714 case PREF_UPDATE:
715 if (entry->setting_type == G_TYPE_STRING)
716 g_free(*(gchararray*)entry->setting);
717 else if (entry->setting_type == G_TYPE_STRV)
718 g_strfreev(*(gchararray**)entry->setting);
719
720 g_object_get(object, name, entry->setting, NULL);
721 break;
722 }
723}
724
725
726static void pref_action(PrefAction action, StashGroup *group, GtkWidget *owner)
727{
729 guint i;
730
732 {
733 GtkWidget *widget;
734
735 /* ignore settings with no widgets */
736 if (entry->widget_type == G_TYPE_NONE)
737 continue;
738
739 /* radio buttons have several widgets */
740 if (entry->widget_type == GTK_TYPE_RADIO_BUTTON)
741 {
742 handle_radio_buttons(owner, entry, action);
743 continue;
744 }
745
746 widget = get_widget(owner, entry->widget_id);
747 if (!widget)
748 {
749 g_warning("Unknown widget for %s::%s in %s()!", group->name, entry->key_name,
750 G_STRFUNC);
751 continue;
752 }
753
754 /* note: can't use switch for GTK_TYPE macros */
755 if (entry->widget_type == GTK_TYPE_TOGGLE_BUTTON)
756 handle_toggle_button(widget, entry->setting, action);
757 else if (entry->widget_type == GTK_TYPE_SPIN_BUTTON)
758 handle_spin_button(widget, entry, action);
759 else if (entry->widget_type == GTK_TYPE_COMBO_BOX)
760 handle_combo_box(widget, entry, action);
761 else if (entry->widget_type == TYPE_COMBO_BOX_ENTRY)
762 handle_combo_box_entry(widget, entry, action);
763 else if (entry->widget_type == GTK_TYPE_ENTRY)
764 handle_entry(widget, entry, action);
765 else if (entry->widget_type == G_TYPE_PARAM)
766 handle_widget_property(widget, entry, action);
767 else
768 g_warning("Unhandled type for %s::%s in %s()!", group->name, entry->key_name,
769 G_STRFUNC);
770 }
771}
772
773
774/** Applies Stash settings to widgets, usually called before displaying the widgets.
775 * The @a owner argument depends on which type you use for @ref StashWidgetID.
776 * @param group .
777 * @param owner If non-NULL, used to lookup widgets by name, otherwise
778 * widget pointers are assumed.
779 * @see stash_group_update(). */
780GEANY_API_SYMBOL
781void stash_group_display(StashGroup *group, GtkWidget *owner)
782{
784}
785
786
787/** Applies widget values to Stash settings, usually called after displaying the widgets.
788 * The @a owner argument depends on which type you use for @ref StashWidgetID.
789 * @param group .
790 * @param owner If non-NULL, used to lookup widgets by name, otherwise
791 * widget pointers are assumed.
792 * @see stash_group_display(). */
793GEANY_API_SYMBOL
794void stash_group_update(StashGroup *group, GtkWidget *owner)
795{
797}
798
799
800static StashPref *
801add_widget_pref(StashGroup *group, GType setting_type, gpointer setting,
802 const gchar *key_name, gpointer default_value,
803 GType widget_type, StashWidgetID widget_id)
804{
806 add_pref(group, setting_type, setting, key_name, default_value);
807
808 entry->widget_type = widget_type;
809 entry->widget_id = widget_id;
810 return entry;
811}
812
813
814/** Adds a @c GtkToggleButton (or @c GtkCheckButton) widget pref.
815 * @param group .
816 * @param setting Address of setting variable.
817 * @param key_name Name for key in a @c GKeyFile.
818 * @param default_value Value to use if the key doesn't exist when loading.
819 * @param widget_id @c GtkWidget pointer or string to lookup widget later.
820 * @see stash_group_add_radio_buttons(). */
821GEANY_API_SYMBOL
823 const gchar *key_name, gboolean default_value, StashWidgetID widget_id)
824{
825 add_widget_pref(group, G_TYPE_BOOLEAN, setting, key_name, GINT_TO_POINTER(default_value),
826 GTK_TYPE_TOGGLE_BUTTON, widget_id);
827}
828
829
830/** Adds a @c GtkRadioButton widget group pref.
831 * @param group .
832 * @param setting Address of setting variable.
833 * @param key_name Name for key in a @c GKeyFile.
834 * @param default_value Value to use if the key doesn't exist when loading.
835 * @param widget_id @c GtkWidget pointer or string to lookup widget later.
836 * @param enum_id Enum value for @a widget_id.
837 * @param ... pairs of @a widget_id, @a enum_id.
838 * Example (using widget lookup strings, but widget pointers can also work):
839 * @code
840 * enum {FOO, BAR};
841 * stash_group_add_radio_buttons(group, &which_one_setting, "which_one", BAR,
842 * "radio_foo", FOO, "radio_bar", BAR, NULL);
843 * @endcode */
844GEANY_API_SYMBOL
846 const gchar *key_name, gint default_value,
847 StashWidgetID widget_id, gint enum_id, ...)
848{
850 add_widget_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value),
851 GTK_TYPE_RADIO_BUTTON, NULL);
852 va_list args;
853 gsize count = 1;
854 EnumWidget *item, *array;
855
856 /* count pairs of args */
857 va_start(args, enum_id);
858 while (1)
859 {
860 if (!va_arg(args, gpointer))
861 break;
862 va_arg(args, gint);
863 count++;
864 }
865 va_end(args);
866
867 array = g_new0(EnumWidget, count + 1);
868 entry->extra.radio_buttons = array;
869
870 va_start(args, enum_id);
871 foreach_c_array(item, array, count)
872 {
873 if (item == array)
874 {
875 /* first element */
876 item->widget_id = widget_id;
877 item->enum_id = enum_id;
878 }
879 else
880 {
881 item->widget_id = va_arg(args, gpointer);
882 item->enum_id = va_arg(args, gint);
883 }
884 }
885 va_end(args);
886}
887
888
889/** Adds a @c GtkSpinButton widget pref.
890 * @param group .
891 * @param setting Address of setting variable.
892 * @param key_name Name for key in a @c GKeyFile.
893 * @param default_value Value to use if the key doesn't exist when loading.
894 * @param widget_id @c GtkWidget pointer or string to lookup widget later. */
895GEANY_API_SYMBOL
897 const gchar *key_name, gint default_value, StashWidgetID widget_id)
898{
899 add_widget_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value),
900 GTK_TYPE_SPIN_BUTTON, widget_id);
901}
902
903
904/** Adds a @c GtkComboBox widget pref.
905 * @param group .
906 * @param setting Address of setting variable.
907 * @param key_name Name for key in a @c GKeyFile.
908 * @param default_value Value to use if the key doesn't exist when loading.
909 * @param widget_id @c GtkWidget pointer or string to lookup widget later.
910 * @see stash_group_add_combo_box_entry(). */
911GEANY_API_SYMBOL
913 const gchar *key_name, gint default_value, StashWidgetID widget_id)
914{
915 add_widget_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value),
916 GTK_TYPE_COMBO_BOX, widget_id);
917}
918
919
920/** Adds a @c GtkComboBoxEntry widget pref.
921 * @param group .
922 * @param setting Address of setting variable.
923 * @param key_name Name for key in a @c GKeyFile.
924 * @param default_value Value to use if the key doesn't exist when loading.
925 * @param widget_id @c GtkWidget pointer or string to lookup widget later. */
926/* We could maybe also have something like stash_group_add_combo_box_entry_with_menu()
927 * for the history list - or should that be stored as a separate setting? */
928GEANY_API_SYMBOL
930 const gchar *key_name, const gchar *default_value, StashWidgetID widget_id)
931{
932 add_widget_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value,
933 TYPE_COMBO_BOX_ENTRY, widget_id);
934}
935
936
937/** Adds a @c GtkEntry widget pref.
938 * @param group .
939 * @param setting Address of setting variable.
940 * @param key_name Name for key in a @c GKeyFile.
941 * @param default_value Value to use if the key doesn't exist when loading.
942 * @param widget_id @c GtkWidget pointer or string to lookup widget later. */
943GEANY_API_SYMBOL
945 const gchar *key_name, const gchar *default_value, StashWidgetID widget_id)
946{
947 add_widget_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value,
948 GTK_TYPE_ENTRY, widget_id);
949}
950
951
952static GType object_get_property_type(GObject *object, const gchar *property_name)
953{
954 GObjectClass *klass = G_OBJECT_GET_CLASS(object);
955 GParamSpec *ps;
956
957 ps = g_object_class_find_property(klass, property_name);
958 return ps->value_type;
959}
960
961
962/** Adds a widget's read/write property to the stash group.
963 * The property will be set when calling
964 * stash_group_display(), and read when calling stash_group_update().
965 * @param group .
966 * @param setting Address of e.g. an integer if using an integer property.
967 * @param key_name Name for key in a @c GKeyFile.
968 * @param default_value Value to use if the key doesn't exist when loading.
969 * Should be cast into a pointer e.g. with @c GINT_TO_POINTER().
970 * @param widget_id @c GtkWidget pointer or string to lookup widget later.
971 * @param property_name .
972 * @param type can be @c 0 if passing a @c GtkWidget as the @a widget_id argument to look it up from the
973 * @c GObject data.
974 * @warning Currently only string GValue properties will be freed before setting; patch for
975 * other types - see @c handle_widget_property(). */
976GEANY_API_SYMBOL
978 const gchar *key_name, gpointer default_value, StashWidgetID widget_id,
979 const gchar *property_name, GType type)
980{
981 if (!type)
982 type = object_get_property_type(G_OBJECT(widget_id), property_name);
983
984 add_widget_pref(group, type, setting, key_name, default_value,
985 G_TYPE_PARAM, widget_id)->extra.property_name = property_name;
986}
987
988
989enum
990{
995
996
998{
999 const gchar *group_name;
1001 struct
1002 {
1003 gchararray tree_string;
1006};
1007
1009
1010
1011static void stash_tree_renderer_set_data(GtkCellLayout *cell_layout, GtkCellRenderer *cell,
1012 GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
1013{
1014 GType cell_type = GPOINTER_TO_SIZE(user_data);
1015 StashTreeValue *value;
1016 StashPref *pref;
1017 gboolean matches_type;
1018
1019 gtk_tree_model_get(model, iter, STASH_TREE_VALUE, &value, -1);
1020 pref = value->pref;
1021 matches_type = pref->setting_type == cell_type;
1022 g_object_set(cell, "visible", matches_type, "sensitive", matches_type,
1023 cell_type == G_TYPE_BOOLEAN ? "activatable" : "editable", matches_type, NULL);
1024
1025 if (matches_type)
1026 {
1027 switch (pref->setting_type)
1028 {
1029 case G_TYPE_BOOLEAN:
1030 g_object_set(cell, "active", value->data.tree_int, NULL);
1031 break;
1032 case G_TYPE_INT:
1033 {
1034 gchar *text = g_strdup_printf("%d", value->data.tree_int);
1035 g_object_set(cell, "text", text, NULL);
1036 g_free(text);
1037 break;
1038 }
1039 case G_TYPE_STRING:
1040 g_object_set(cell, "text", value->data.tree_string, NULL);
1041 break;
1042 }
1043 }
1044}
1045
1046
1047static void stash_tree_renderer_edited(gchar *path_str, gchar *new_text, GtkTreeModel *model)
1048{
1049 GtkTreePath *path;
1050 GtkTreeIter iter;
1051 StashTreeValue *value;
1052 StashPref *pref;
1053
1054 path = gtk_tree_path_new_from_string(path_str);
1055 gtk_tree_model_get_iter(model, &iter, path);
1056 gtk_tree_model_get(model, &iter, STASH_TREE_VALUE, &value, -1);
1057 pref = value->pref;
1058
1059 switch (pref->setting_type)
1060 {
1061 case G_TYPE_BOOLEAN:
1062 value->data.tree_int = !value->data.tree_int;
1063 break;
1064 case G_TYPE_INT:
1065 value->data.tree_int = atoi(new_text);
1066 break;
1067 case G_TYPE_STRING:
1068 SETPTR(value->data.tree_string, g_strdup(new_text));
1069 break;
1070 }
1071
1072 gtk_tree_model_row_changed(model, path, &iter);
1073 gtk_tree_path_free(path);
1074}
1075
1076
1077static void stash_tree_boolean_toggled(GtkCellRendererToggle *cell, gchar *path_str,
1078 GtkTreeModel *model)
1079{
1080 stash_tree_renderer_edited(path_str, NULL, model);
1081}
1082
1083
1084static void stash_tree_string_edited(GtkCellRenderer *cell, gchar *path_str, gchar *new_text,
1085 GtkTreeModel *model)
1086{
1087 stash_tree_renderer_edited(path_str, new_text, model);
1088}
1089
1090
1091static gboolean stash_tree_discard_value(GtkTreeModel *model, GtkTreePath *path,
1092 GtkTreeIter *iter, gpointer user_data)
1093{
1094 StashTreeValue *value;
1095
1096 gtk_tree_model_get(model, iter, STASH_TREE_VALUE, &value, -1);
1097 /* don't access value->pref as it might already have been freed */
1098 g_free(value->data.tree_string);
1099 g_free(value);
1100
1101 return FALSE;
1102}
1103
1104
1105static void stash_tree_destroy_cb(GtkWidget *widget, gpointer user_data)
1106{
1107 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1108 gtk_tree_model_foreach(model, stash_tree_discard_value, NULL);
1109}
1110
1111
1112static void stash_tree_append_pref(StashGroup *group, StashPref *entry, GtkListStore *store,
1113 PrefAction action)
1114{
1115 GtkTreeIter iter;
1116 StashTreeValue *value;
1117 gchar *text = NULL;
1118
1119 value = g_new0(StashTreeValue, 1);
1120
1121 value->group_name = group->name;
1122 value->pref = entry;
1123
1124 gtk_list_store_append(store, &iter);
1125 text = g_strconcat(group->prefix ? group->prefix : group->name,
1126 ".", entry->key_name, NULL);
1127 gtk_list_store_set(store, &iter, STASH_TREE_NAME, text,
1128 STASH_TREE_VALUE, value, -1);
1129 g_free(text);
1130}
1131
1132
1133static void stash_tree_append_prefs(GPtrArray *group_array,
1134 GtkListStore *store, PrefAction action)
1135{
1137 guint i, j;
1139
1140 foreach_ptr_array(group, i, group_array)
1141 {
1142 if (group->various)
1143 {
1145 stash_tree_append_pref(group, entry, store, action);
1146 }
1147 }
1148}
1149
1150
1151/* Setups a simple editor for stash preferences based on the widget arguments.
1152 * group_array - Array of groups which's settings will be edited.
1153 * tree - GtkTreeView in which to edit the preferences. Must be empty. */
1154void stash_tree_setup(GPtrArray *group_array, GtkTreeView *tree)
1155{
1156 GtkListStore *store;
1157 GtkTreeModel *model;
1158 GtkCellRenderer *cell;
1159 GtkTreeViewColumn *column;
1160 GtkAdjustment *adjustment;
1161
1162 store = gtk_list_store_new(STASH_TREE_COUNT, G_TYPE_STRING, G_TYPE_POINTER);
1163 stash_tree_append_prefs(group_array, store, PREF_DISPLAY);
1164 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), STASH_TREE_NAME,
1165 GTK_SORT_ASCENDING);
1166
1167 model = GTK_TREE_MODEL(store);
1168 gtk_tree_view_set_model(tree, model);
1169 g_object_unref(G_OBJECT(store));
1170 g_signal_connect(tree, "destroy", G_CALLBACK(stash_tree_destroy_cb), NULL);
1171
1172 cell = gtk_cell_renderer_text_new();
1173 column = gtk_tree_view_column_new_with_attributes(_("Name"), cell, "text",
1175 gtk_tree_view_column_set_sort_column_id(column, STASH_TREE_NAME);
1176 gtk_tree_view_column_set_sort_indicator(column, TRUE);
1177 gtk_tree_view_append_column(tree, column);
1178
1179 column = gtk_tree_view_column_new();
1180 gtk_tree_view_column_set_title(column, _("Value"));
1181 gtk_tree_view_append_column(tree, column);
1182 /* boolean renderer */
1183 cell = gtk_cell_renderer_toggle_new();
1184 g_signal_connect(cell, "toggled", G_CALLBACK(stash_tree_boolean_toggled), model);
1185 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), cell, FALSE);
1186 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(column), cell,
1187 stash_tree_renderer_set_data, GSIZE_TO_POINTER(G_TYPE_BOOLEAN), NULL);
1188 /* string renderer */
1189 cell = gtk_cell_renderer_text_new();
1190 g_object_set(cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1191 g_signal_connect(cell, "edited", G_CALLBACK(stash_tree_string_edited), model);
1192 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), cell, TRUE);
1193 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(column), cell,
1194 stash_tree_renderer_set_data, GSIZE_TO_POINTER(G_TYPE_STRING), NULL);
1195 /* integer renderer */
1196 cell = gtk_cell_renderer_spin_new();
1197 adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, G_MININT, G_MAXINT, 1, 10, 0));
1198 g_object_set(cell, "adjustment", adjustment, NULL);
1199 g_signal_connect(cell, "edited", G_CALLBACK(stash_tree_string_edited), model);
1200 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), cell, FALSE);
1201 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(column), cell,
1202 stash_tree_renderer_set_data, GSIZE_TO_POINTER(G_TYPE_INT), NULL);
1203}
1204
1205
1207{
1208 switch (entry->setting_type)
1209 {
1210 case G_TYPE_BOOLEAN:
1211 value->data.tree_int = *(gboolean *) entry->setting;
1212 break;
1213 case G_TYPE_INT:
1214 value->data.tree_int = *(gint *) entry->setting;
1215 break;
1216 case G_TYPE_STRING:
1217 SETPTR(value->data.tree_string, g_strdup(*(gchararray *) entry->setting));
1218 break;
1219 default:
1220 g_warning("Unhandled type for %s::%s in %s()!", value->group_name,
1221 entry->key_name, G_STRFUNC);
1222 }
1223}
1224
1225
1227{
1228 switch (entry->setting_type)
1229 {
1230 case G_TYPE_BOOLEAN:
1231 *(gboolean *) entry->setting = value->data.tree_int;
1232 break;
1233 case G_TYPE_INT:
1234 *(gint *) entry->setting = value->data.tree_int;
1235 break;
1236 case G_TYPE_STRING:
1237 {
1238 gchararray *text = entry->setting;
1239 SETPTR(*text, g_strdup(value->data.tree_string));
1240 break;
1241 }
1242 default:
1243 g_warning("Unhandled type for %s::%s in %s()!", value->group_name,
1244 entry->key_name, G_STRFUNC);
1245 }
1246}
1247
1248
1249static void stash_tree_action(GtkTreeModel *model, PrefAction action)
1250{
1251 GtkTreeIter iter;
1252 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
1253 StashTreeValue *value;
1254
1255 while (valid)
1256 {
1257 gtk_tree_model_get(model, &iter, STASH_TREE_VALUE, &value, -1);
1258
1259 switch (action)
1260 {
1261 case PREF_DISPLAY:
1262 stash_tree_display_pref(value, value->pref);
1263 break;
1264 case PREF_UPDATE:
1265 stash_tree_update_pref(value, value->pref);
1266 break;
1267 }
1268 valid = gtk_tree_model_iter_next(model, &iter);
1269 }
1270}
1271
1272
1273void stash_tree_display(GtkTreeView *tree)
1274{
1275 stash_tree_action(gtk_tree_view_get_model(tree), PREF_DISPLAY);
1276}
1277
1278
1279void stash_tree_update(GtkTreeView *tree)
1280{
1281 stash_tree_action(gtk_tree_view_get_model(tree), PREF_UPDATE);
1282}
const gchar * name
Definition: document.c:3219
gchar * text
Definition: editor.c:83
#define field(x)
unsigned int count
SettingAction
Definition: keyfile.c:303
static gboolean dummy
Definition: libmain.c:115
#define NULL
Definition: rbtree.h:150
GtkWidget * entry
Definition: search.c:118
static StashGroup * stash_group
Definition: sidebar.c:1057
StashGroup * group
Definition: stash-example.c:1
const gchar filename[]
Definition: stash-example.c:4
void stash_group_add_combo_box_entry(StashGroup *group, gchar **setting, const gchar *key_name, const gchar *default_value, StashWidgetID widget_id)
Adds a GtkComboBoxEntry widget pref.
Definition: stash.c:929
static void stash_tree_append_prefs(GPtrArray *group_array, GtkListStore *store, PrefAction action)
Definition: stash.c:1133
static void handle_entry(GtkWidget *widget, StashPref *entry, PrefAction action)
Definition: stash.c:575
void stash_group_free_settings(StashGroup *group)
Frees the memory allocated for setting values in a group.
Definition: stash.c:377
void stash_group_add_spin_button_integer(StashGroup *group, gint *setting, const gchar *key_name, gint default_value, StashWidgetID widget_id)
Adds a GtkSpinButton widget pref.
Definition: stash.c:896
static void stash_tree_renderer_edited(gchar *path_str, gchar *new_text, GtkTreeModel *model)
Definition: stash.c:1047
static void stash_tree_destroy_cb(GtkWidget *widget, gpointer user_data)
Definition: stash.c:1105
static void stash_tree_boolean_toggled(GtkCellRendererToggle *cell, gchar *path_str, GtkTreeModel *model)
Definition: stash.c:1077
static void handle_integer_setting(StashGroup *group, StashPref *se, GKeyFile *config, SettingAction action)
Definition: stash.c:170
static gboolean stash_tree_discard_value(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
Definition: stash.c:1091
void stash_group_add_radio_buttons(StashGroup *group, gint *setting, const gchar *key_name, gint default_value, StashWidgetID widget_id, gint enum_id,...)
Adds a GtkRadioButton widget group pref.
Definition: stash.c:845
void stash_group_add_string(StashGroup *group, gchar **setting, const gchar *key_name, const gchar *default_value)
Adds string setting.
Definition: stash.c:499
void stash_group_add_toggle_button(StashGroup *group, gboolean *setting, const gchar *key_name, gboolean default_value, StashWidgetID widget_id)
Adds a GtkToggleButton (or GtkCheckButton) widget pref.
Definition: stash.c:822
static void handle_combo_box_entry(GtkWidget *widget, StashPref *entry, PrefAction action)
Definition: stash.c:593
void stash_group_display(StashGroup *group, GtkWidget *owner)
Applies Stash settings to widgets, usually called before displaying the widgets.
Definition: stash.c:781
void stash_group_save_to_key_file(StashGroup *group, GKeyFile *keyfile)
Writes group settings into key values in keyfile.
Definition: stash.c:286
gint stash_group_save_to_file(StashGroup *group, const gchar *filename, GKeyFileFlags flags)
Writes group settings to a configuration file using GKeyFile.
Definition: stash.c:326
static void keyfile_action(SettingAction action, StashGroup *group, GKeyFile *keyfile)
Definition: stash.c:237
#define TYPE_COMBO_BOX_ENTRY
Definition: stash.c:88
static void handle_radio_button(GtkWidget *widget, gint enum_id, gboolean *setting, PrefAction action)
Definition: stash.c:649
static void stash_tree_string_edited(GtkCellRenderer *cell, gchar *path_str, gchar *new_text, GtkTreeModel *model)
Definition: stash.c:1084
void stash_tree_setup(GPtrArray *group_array, GtkTreeView *tree)
Definition: stash.c:1154
static StashPref * add_pref(StashGroup *group, GType type, gpointer setting, const gchar *key_name, gpointer default_value)
Definition: stash.c:447
GType stash_group_get_type(void)
Gets the GBoxed-derived GType for StashGroup.
static void stash_tree_update_pref(StashTreeValue *value, StashPref *entry)
Definition: stash.c:1226
void stash_group_add_integer(StashGroup *group, gint *setting, const gchar *key_name, gint default_value)
Adds integer setting.
Definition: stash.c:485
void stash_group_add_string_vector(StashGroup *group, gchar ***setting, const gchar *key_name, const gchar **default_value)
Adds string vector setting (array of strings).
Definition: stash.c:513
static void handle_radio_buttons(GtkWidget *owner, StashPref *entry, PrefAction action)
Definition: stash.c:666
gboolean stash_group_load_from_file(StashGroup *group, const gchar *filename)
Reads group settings from a configuration file using GKeyFile.
Definition: stash.c:301
struct EnumWidget EnumWidget
static void handle_toggle_button(GtkWidget *widget, gboolean *setting, PrefAction action)
Definition: stash.c:522
static StashPref * add_widget_pref(StashGroup *group, GType setting_type, gpointer setting, const gchar *key_name, gpointer default_value, GType widget_type, StashWidgetID widget_id)
Definition: stash.c:801
static void handle_spin_button(GtkWidget *widget, StashPref *entry, PrefAction action)
Definition: stash.c:537
static void handle_combo_box(GtkWidget *widget, StashPref *entry, PrefAction action)
Definition: stash.c:558
void stash_group_load_from_key_file(StashGroup *group, GKeyFile *keyfile)
Reads key values from keyfile into the group settings.
Definition: stash.c:275
static void handle_widget_property(GtkWidget *widget, StashPref *entry, PrefAction action)
Definition: stash.c:691
static void free_stash_pref(StashPref *pref)
Definition: stash.c:347
static void handle_boolean_setting(StashGroup *group, StashPref *se, GKeyFile *config, SettingAction action)
Definition: stash.c:152
static GType get_combo_box_entry_type(void)
Definition: stash.c:89
void stash_group_update(StashGroup *group, GtkWidget *owner)
Applies widget values to Stash settings, usually called after displaying the widgets.
Definition: stash.c:794
SettingAction
Definition: stash.c:138
@ SETTING_WRITE
Definition: stash.c:140
@ SETTING_READ
Definition: stash.c:139
void stash_group_add_combo_box(StashGroup *group, gint *setting, const gchar *key_name, gint default_value, StashWidgetID widget_id)
Adds a GtkComboBox widget pref.
Definition: stash.c:912
static GtkWidget * get_widget(GtkWidget *owner, StashWidgetID widget_id)
Definition: stash.c:631
static GType object_get_property_type(GObject *object, const gchar *property_name)
Definition: stash.c:952
void stash_tree_update(GtkTreeView *tree)
Definition: stash.c:1279
void stash_group_set_use_defaults(StashGroup *group, gboolean use_defaults)
Definition: stash.c:440
void stash_group_add_boolean(StashGroup *group, gboolean *setting, const gchar *key_name, gboolean default_value)
Adds boolean setting.
Definition: stash.c:472
StashGroup * stash_group_new(const gchar *name)
Creates a new group.
Definition: stash.c:360
static void stash_tree_renderer_set_data(GtkCellLayout *cell_layout, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
Definition: stash.c:1011
void stash_tree_display(GtkTreeView *tree)
Definition: stash.c:1273
void stash_group_add_widget_property(StashGroup *group, gpointer setting, const gchar *key_name, gpointer default_value, StashWidgetID widget_id, const gchar *property_name, GType type)
Adds a widget's read/write property to the stash group.
Definition: stash.c:977
G_DEFINE_BOXED_TYPE(StashGroup, stash_group, stash_group_dup, stash_group_free)
PrefAction
Definition: stash.c:145
@ PREF_UPDATE
Definition: stash.c:147
@ PREF_DISPLAY
Definition: stash.c:146
void stash_group_free(StashGroup *group)
Frees a group.
Definition: stash.c:407
void stash_group_set_various(StashGroup *group, gboolean various, const gchar *prefix)
Definition: stash.c:429
@ STASH_TREE_NAME
Definition: stash.c:991
@ STASH_TREE_COUNT
Definition: stash.c:993
@ STASH_TREE_VALUE
Definition: stash.c:992
static void stash_tree_action(GtkTreeModel *model, PrefAction action)
Definition: stash.c:1249
static void handle_strv_setting(StashGroup *group, StashPref *se, GKeyFile *config, SettingAction action)
Definition: stash.c:208
static void pref_action(PrefAction action, StashGroup *group, GtkWidget *owner)
Definition: stash.c:726
static StashGroup * stash_group_dup(StashGroup *src)
Definition: stash.c:396
static void stash_tree_display_pref(StashTreeValue *value, StashPref *entry)
Definition: stash.c:1206
void stash_group_add_entry(StashGroup *group, gchar **setting, const gchar *key_name, const gchar *default_value, StashWidgetID widget_id)
Adds a GtkEntry widget pref.
Definition: stash.c:944
static GtkWidget * lookup_widget(GtkWidget *widget, const gchar *widget_name)
Definition: stash.c:603
static void handle_string_setting(StashGroup *group, StashPref *se, GKeyFile *config, SettingAction action)
Definition: stash.c:188
static void stash_tree_append_pref(StashGroup *group, StashPref *entry, GtkListStore *store, PrefAction action)
Definition: stash.c:1112
Lightweight library for reading/writing GKeyFile settings and synchronizing widgets with C variables.
gconstpointer StashWidgetID
Can be GtkWidget* or gchar* depending on whether the owner argument is used for stash_group_display()...
Definition: stash.h:33
StashWidgetID widget_id
Definition: stash.c:131
gint enum_id
Definition: stash.c:132
gboolean use_defaults
Definition: stash.c:126
const gchar * name
Definition: stash.c:122
const gchar * prefix
Definition: stash.c:125
gboolean various
Definition: stash.c:124
GPtrArray * entries
Definition: stash.c:123
guint refcount
Definition: stash.c:121
gpointer setting
Definition: stash.c:105
GType setting_type
Definition: stash.c:104
GType widget_type
Definition: stash.c:108
const gchar * key_name
Definition: stash.c:106
StashWidgetID widget_id
Definition: stash.c:109
struct EnumWidget * radio_buttons
Definition: stash.c:112
union StashPref::@117 extra
const gchar * property_name
Definition: stash.c:113
gpointer default_value
Definition: stash.c:107
gint tree_int
Definition: stash.c:1004
struct StashTreeValue::@118 data
const gchar * group_name
Definition: stash.c:999
StashPref * pref
Definition: stash.c:1000
gchararray tree_string
Definition: stash.c:1003
Defines internationalization macros.
#define _(String)
Definition: support.h:42
gint utils_write_file(const gchar *filename, const gchar *text)
Writes text into a file named filename.
Definition: utils.c:209
gint utils_get_setting_integer(GKeyFile *config, const gchar *section, const gchar *key, const gint default_value)
Wraps g_key_file_get_integer() to add a default value argument.
Definition: utils.c:805
gboolean utils_get_setting_boolean(GKeyFile *config, const gchar *section, const gchar *key, const gboolean default_value)
Wraps g_key_file_get_boolean() to add a default value argument.
Definition: utils.c:836
gchar * utils_get_setting_string(GKeyFile *config, const gchar *section, const gchar *key, const gchar *default_value)
Wraps g_key_file_get_string() to add a default value argument.
Definition: utils.c:867
General utility functions, non-GTK related.
#define foreach_ptr_array(item, idx, ptr_array)
Iterates all the pointers in ptr_array.
Definition: utils.h:108
#define foreach_c_array(item, array, len)
Iterates all the items in array using pointers.
Definition: utils.h:94
#define SETPTR(ptr, result)
Assigns result to ptr, then frees the old value.
Definition: utils.h:50