2008-11-28 12:52:19 +00:00
|
|
|
/*
|
|
|
|
* stash.c - this file is part of Geany, a fast and lightweight IDE
|
|
|
|
*
|
|
|
|
* Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
|
|
|
|
* Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
* MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Mini-library for reading/writing GKeyFile settings and synchronizing widgets with
|
|
|
|
* C variables. */
|
|
|
|
|
2008-12-22 17:13:37 +00:00
|
|
|
/* Terms
|
|
|
|
* 'Setting' is used only for data stored on disk or in memory.
|
|
|
|
* 'Pref' can also include visual widget information.
|
2008-12-22 16:14:48 +00:00
|
|
|
*
|
2008-12-22 17:13:37 +00:00
|
|
|
* Memory Usage
|
|
|
|
* Stash will not duplicate strings if they are normally static arrays, such as
|
|
|
|
* keyfile group names and key names, string default values or widget_id names.
|
|
|
|
* String settings and other dynamically allocated settings must be initialized to NULL.
|
|
|
|
*/
|
2008-12-11 13:25:08 +00:00
|
|
|
|
2008-12-22 18:18:14 +00:00
|
|
|
/* Implementation Note
|
|
|
|
* We use a GArray to hold prefs. It would be more efficient for user code to declare
|
|
|
|
* a static array of GeanyPrefEntry structs, but we don't do this because:
|
|
|
|
*
|
|
|
|
* * It would be more ugly (lots of casts and NULLs).
|
|
|
|
* * Less type checking.
|
|
|
|
* * The API would have to break when adding/changing fields.
|
|
|
|
*
|
|
|
|
* Usually the prefs code isn't what user code will spend most of its time doing, so this
|
|
|
|
* should be efficient enough. But, if desired we could add a stash_group_set_size() function
|
|
|
|
* to reduce reallocation.
|
|
|
|
* */
|
|
|
|
|
2008-11-28 12:52:19 +00:00
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
#include "stash.h"
|
2008-12-22 17:13:37 +00:00
|
|
|
#include "utils.h" /* only for utils_get_setting_*(). Stash should not depend on Geany. */
|
2008-11-28 12:52:19 +00:00
|
|
|
|
2008-12-09 13:16:52 +00:00
|
|
|
#define foreach_array(type, item, array) \
|
|
|
|
foreach_c_array(item, ((type*)(gpointer)array->data), array->len)
|
|
|
|
|
|
|
|
|
|
|
|
struct GeanyPrefEntry
|
|
|
|
{
|
2008-12-22 16:14:48 +00:00
|
|
|
GType setting_type; /* e.g. G_TYPE_INT */
|
2008-12-09 13:16:52 +00:00
|
|
|
gpointer setting;
|
|
|
|
const gchar *key_name;
|
|
|
|
gpointer default_value;
|
2008-12-11 12:49:26 +00:00
|
|
|
GType widget_type; /* e.g. GTK_TYPE_TOGGLE_BUTTON */
|
|
|
|
gpointer widget_id; /* can be GtkWidget or gchararray */
|
2008-12-15 13:02:29 +00:00
|
|
|
gpointer fields; /* extra fields */
|
2008-12-09 13:16:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct GeanyPrefGroup
|
|
|
|
{
|
|
|
|
const gchar *name; /* group name to use in the keyfile */
|
|
|
|
GArray *entries; /* array of GeanyPrefEntry */
|
|
|
|
gboolean write_once; /* only write settings if they don't already exist */
|
2008-12-27 12:55:04 +00:00
|
|
|
gboolean use_defaults; /* use default values if there's no keyfile entry */
|
2008-12-09 13:16:52 +00:00
|
|
|
};
|
|
|
|
|
2008-12-15 13:02:29 +00:00
|
|
|
typedef struct EnumWidget
|
|
|
|
{
|
|
|
|
gpointer widget_id;
|
|
|
|
gint enum_id;
|
|
|
|
}
|
|
|
|
EnumWidget;
|
|
|
|
|
2008-11-28 12:52:19 +00:00
|
|
|
|
|
|
|
typedef enum SettingAction
|
|
|
|
{
|
|
|
|
SETTING_READ,
|
|
|
|
SETTING_WRITE
|
|
|
|
}
|
|
|
|
SettingAction;
|
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
typedef enum PrefAction
|
|
|
|
{
|
|
|
|
PREF_DISPLAY,
|
|
|
|
PREF_UPDATE
|
|
|
|
}
|
|
|
|
PrefAction;
|
2008-11-28 12:52:19 +00:00
|
|
|
|
|
|
|
|
2008-12-09 13:16:52 +00:00
|
|
|
static void handle_boolean_setting(GeanyPrefGroup *group, GeanyPrefEntry *se,
|
2008-11-28 12:52:19 +00:00
|
|
|
GKeyFile *config, SettingAction action)
|
|
|
|
{
|
|
|
|
gboolean *setting = se->setting;
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case SETTING_READ:
|
|
|
|
*setting = utils_get_setting_boolean(config, group->name, se->key_name,
|
|
|
|
GPOINTER_TO_INT(se->default_value));
|
|
|
|
break;
|
|
|
|
case SETTING_WRITE:
|
|
|
|
g_key_file_set_boolean(config, group->name, se->key_name, *setting);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-09 13:16:52 +00:00
|
|
|
static void handle_integer_setting(GeanyPrefGroup *group, GeanyPrefEntry *se,
|
2008-11-28 12:52:19 +00:00
|
|
|
GKeyFile *config, SettingAction action)
|
|
|
|
{
|
|
|
|
gboolean *setting = se->setting;
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case SETTING_READ:
|
|
|
|
*setting = utils_get_setting_integer(config, group->name, se->key_name,
|
|
|
|
GPOINTER_TO_INT(se->default_value));
|
|
|
|
break;
|
|
|
|
case SETTING_WRITE:
|
|
|
|
g_key_file_set_integer(config, group->name, se->key_name, *setting);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-01 14:54:47 +00:00
|
|
|
static void handle_string_setting(GeanyPrefGroup *group, GeanyPrefEntry *se,
|
|
|
|
GKeyFile *config, SettingAction action)
|
|
|
|
{
|
|
|
|
gchararray *setting = se->setting;
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case SETTING_READ:
|
|
|
|
g_free(*setting);
|
|
|
|
*setting = utils_get_setting_string(config, group->name, se->key_name,
|
|
|
|
se->default_value);
|
|
|
|
break;
|
|
|
|
case SETTING_WRITE:
|
|
|
|
g_key_file_set_string(config, group->name, se->key_name, *setting);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
static void keyfile_action(SettingAction action, GeanyPrefGroup *group, GKeyFile *keyfile)
|
2008-11-28 12:52:19 +00:00
|
|
|
{
|
|
|
|
GeanyPrefEntry *entry;
|
|
|
|
|
2008-12-09 13:16:52 +00:00
|
|
|
foreach_array(GeanyPrefEntry, entry, group->entries)
|
2008-11-28 12:52:19 +00:00
|
|
|
{
|
2008-12-27 12:55:04 +00:00
|
|
|
/* don't overwrite write_once prefs */
|
2008-11-28 12:52:19 +00:00
|
|
|
if (group->write_once && action == SETTING_WRITE &&
|
|
|
|
g_key_file_has_key(keyfile, group->name, entry->key_name, NULL))
|
2008-12-27 12:55:04 +00:00
|
|
|
continue;
|
|
|
|
/* don't override settings with default values */
|
|
|
|
if (!group->use_defaults && action == SETTING_READ &&
|
|
|
|
!g_key_file_has_key(keyfile, group->name, entry->key_name, NULL))
|
|
|
|
continue;
|
2008-11-28 12:52:19 +00:00
|
|
|
|
2008-12-22 16:14:48 +00:00
|
|
|
switch (entry->setting_type)
|
2008-11-28 12:52:19 +00:00
|
|
|
{
|
|
|
|
case G_TYPE_BOOLEAN:
|
2008-12-09 13:16:52 +00:00
|
|
|
handle_boolean_setting(group, entry, keyfile, action); break;
|
2008-11-28 12:52:19 +00:00
|
|
|
case G_TYPE_INT:
|
2008-12-09 13:16:52 +00:00
|
|
|
handle_integer_setting(group, entry, keyfile, action); break;
|
2008-12-01 14:54:47 +00:00
|
|
|
case G_TYPE_STRING:
|
|
|
|
handle_string_setting(group, entry, keyfile, action); break;
|
2008-11-28 12:52:19 +00:00
|
|
|
default:
|
2008-12-11 12:49:26 +00:00
|
|
|
g_warning("Unhandled type for %s::%s in %s!", group->name, entry->key_name,
|
|
|
|
G_GNUC_FUNCTION);
|
2008-11-28 12:52:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 12:50:19 +00:00
|
|
|
void stash_group_load_from_key_file(GeanyPrefGroup *group, GKeyFile *keyfile)
|
2008-11-28 12:52:19 +00:00
|
|
|
{
|
2008-12-11 12:49:26 +00:00
|
|
|
keyfile_action(SETTING_READ, group, keyfile);
|
2008-11-28 12:52:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 12:50:19 +00:00
|
|
|
void stash_group_save_to_key_file(GeanyPrefGroup *group, GKeyFile *keyfile)
|
2008-11-28 12:52:19 +00:00
|
|
|
{
|
2008-12-11 12:49:26 +00:00
|
|
|
keyfile_action(SETTING_WRITE, group, keyfile);
|
2008-11-28 12:52:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-09 13:16:52 +00:00
|
|
|
GeanyPrefGroup *stash_group_new(const gchar *name)
|
|
|
|
{
|
|
|
|
GeanyPrefGroup *group = g_new0(GeanyPrefGroup, 1);
|
|
|
|
|
|
|
|
group->name = name;
|
|
|
|
group->entries = g_array_new(FALSE, FALSE, sizeof(GeanyPrefEntry));
|
2008-12-27 12:55:04 +00:00
|
|
|
group->use_defaults = TRUE;
|
2008-12-09 13:16:52 +00:00
|
|
|
return group;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void stash_group_free(GeanyPrefGroup *group)
|
|
|
|
{
|
2008-12-15 13:02:29 +00:00
|
|
|
GeanyPrefEntry *entry;
|
|
|
|
|
|
|
|
foreach_array(GeanyPrefEntry, entry, group->entries)
|
|
|
|
{
|
|
|
|
if (entry->widget_type == GTK_TYPE_RADIO_BUTTON)
|
|
|
|
g_free(entry->fields);
|
|
|
|
else
|
|
|
|
g_assert(entry->fields == NULL);
|
|
|
|
}
|
2008-12-09 13:16:52 +00:00
|
|
|
g_array_free(group->entries, TRUE);
|
|
|
|
g_free(group);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-27 12:55:04 +00:00
|
|
|
/* Useful so the user can edit the keyfile manually while the program is running,
|
|
|
|
* and the setting won't be overridden.
|
|
|
|
* @c FALSE by default. */
|
2008-12-09 13:16:52 +00:00
|
|
|
void stash_group_set_write_once(GeanyPrefGroup *group, gboolean write_once)
|
|
|
|
{
|
|
|
|
group->write_once = write_once;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-27 12:55:04 +00:00
|
|
|
/* When @c FALSE, Stash doesn't change the setting if there is no keyfile entry, so it
|
|
|
|
* remains whatever it was initialized/set to by user code.
|
|
|
|
* @c TRUE by default. */
|
|
|
|
void stash_group_set_use_defaults(GeanyPrefGroup *group, gboolean use_defaults)
|
|
|
|
{
|
|
|
|
group->use_defaults = use_defaults;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
static GeanyPrefEntry *
|
|
|
|
add_pref(GeanyPrefGroup *group, GType type, gpointer setting,
|
2008-12-09 13:16:52 +00:00
|
|
|
const gchar *key_name, gpointer default_value)
|
|
|
|
{
|
2008-12-15 13:02:29 +00:00
|
|
|
GeanyPrefEntry entry = {type, setting, key_name, default_value, G_TYPE_NONE, NULL, NULL};
|
2008-12-11 12:49:26 +00:00
|
|
|
GArray *array = group->entries;
|
2008-12-09 13:16:52 +00:00
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
g_array_append_val(array, entry);
|
|
|
|
|
|
|
|
return &g_array_index(array, GeanyPrefEntry, array->len - 1);
|
2008-12-09 13:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void stash_group_add_boolean(GeanyPrefGroup *group, gboolean *setting,
|
|
|
|
const gchar *key_name, gboolean default_value)
|
|
|
|
{
|
|
|
|
add_pref(group, G_TYPE_BOOLEAN, setting, key_name, GINT_TO_POINTER(default_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void stash_group_add_integer(GeanyPrefGroup *group, gint *setting,
|
|
|
|
const gchar *key_name, gint default_value)
|
|
|
|
{
|
|
|
|
add_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 17:13:37 +00:00
|
|
|
/* The contents of @a setting will be freed before being replaced, so make sure it is
|
|
|
|
* initialized to @c NULL.
|
|
|
|
* @param default_value Not duplicated. */
|
2008-12-09 13:16:52 +00:00
|
|
|
void stash_group_add_string(GeanyPrefGroup *group, gchar **setting,
|
|
|
|
const gchar *key_name, const gchar *default_value)
|
|
|
|
{
|
2008-12-11 13:25:08 +00:00
|
|
|
add_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value);
|
2008-12-09 13:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 12:50:19 +00:00
|
|
|
/* *** GTK-related functions *** */
|
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
static void handle_toggle_button(GtkWidget *widget, gboolean *setting,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case PREF_DISPLAY:
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *setting);
|
|
|
|
break;
|
|
|
|
case PREF_UPDATE:
|
|
|
|
*setting = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 16:03:16 +00:00
|
|
|
static void handle_spin_button(GtkWidget *widget, GeanyPrefEntry *entry,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
gint *setting = entry->setting;
|
|
|
|
|
2008-12-22 16:14:48 +00:00
|
|
|
g_assert(entry->setting_type == G_TYPE_INT); /* only int spin prefs */
|
2008-12-22 16:03:16 +00:00
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case PREF_DISPLAY:
|
|
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), *setting);
|
|
|
|
break;
|
|
|
|
case PREF_UPDATE:
|
|
|
|
*setting = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void handle_combo_box(GtkWidget *widget, GeanyPrefEntry *entry,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
gint *setting = entry->setting;
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case PREF_DISPLAY:
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), *setting);
|
|
|
|
break;
|
|
|
|
case PREF_UPDATE:
|
|
|
|
*setting = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 17:13:37 +00:00
|
|
|
static void handle_entry(GtkWidget *widget, GeanyPrefEntry *entry,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
gchararray *setting = entry->setting;
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case PREF_DISPLAY:
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(widget), *setting);
|
|
|
|
break;
|
|
|
|
case PREF_UPDATE:
|
|
|
|
g_free(*setting);
|
|
|
|
*setting = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void handle_combo_box_entry(GtkWidget *widget, GeanyPrefEntry *entry,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
widget = gtk_bin_get_child(GTK_BIN(widget));
|
|
|
|
handle_entry(widget, entry, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
/* taken from Glade 2.x generated support.c */
|
|
|
|
static GtkWidget*
|
|
|
|
lookup_widget (GtkWidget *widget,
|
|
|
|
const gchar *widget_name)
|
|
|
|
{
|
|
|
|
GtkWidget *parent, *found_widget;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (GTK_IS_MENU (widget))
|
|
|
|
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
|
|
|
|
else
|
|
|
|
parent = widget->parent;
|
|
|
|
if (!parent)
|
|
|
|
parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
|
|
|
|
if (parent == NULL)
|
|
|
|
break;
|
|
|
|
widget = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), widget_name);
|
|
|
|
if (!found_widget)
|
|
|
|
g_warning ("Widget not found: %s", widget_name);
|
|
|
|
return found_widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-15 13:02:29 +00:00
|
|
|
static GtkWidget *
|
|
|
|
get_widget(GtkWidget *owner, gpointer widget_id)
|
|
|
|
{
|
|
|
|
GtkWidget *widget = widget_id;
|
|
|
|
|
|
|
|
if (owner)
|
|
|
|
{
|
|
|
|
const gchar *widget_name = widget_id;
|
|
|
|
|
|
|
|
widget = lookup_widget(owner, widget_name);
|
|
|
|
}
|
|
|
|
if (!GTK_IS_WIDGET(widget))
|
|
|
|
{
|
|
|
|
g_warning("Unknown widget in %s!", G_GNUC_FUNCTION);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void handle_radio_button(GtkWidget *widget, gint enum_id, gboolean *setting,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case PREF_DISPLAY:
|
|
|
|
if (*setting == enum_id)
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
|
|
|
|
break;
|
|
|
|
case PREF_UPDATE:
|
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
|
|
|
|
*setting = enum_id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void handle_radio_buttons(GtkWidget *owner, EnumWidget *fields,
|
|
|
|
gboolean *setting,
|
|
|
|
PrefAction action)
|
|
|
|
{
|
|
|
|
EnumWidget *field = fields;
|
|
|
|
gsize count = 0;
|
|
|
|
GtkWidget *widget = NULL;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
widget = get_widget(owner, field->widget_id);
|
|
|
|
|
|
|
|
if (!widget)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
count++;
|
|
|
|
handle_radio_button(widget, field->enum_id, setting, action);
|
|
|
|
field++;
|
|
|
|
if (!field->widget_id)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (g_slist_length(gtk_radio_button_get_group(GTK_RADIO_BUTTON(widget))) != count)
|
|
|
|
g_warning("Missing/invalid radio button widget IDs found!");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-11 12:49:26 +00:00
|
|
|
static void pref_action(PrefAction action, GeanyPrefGroup *group, GtkWidget *owner)
|
|
|
|
{
|
|
|
|
GeanyPrefEntry *entry;
|
|
|
|
|
|
|
|
foreach_array(GeanyPrefEntry, entry, group->entries)
|
|
|
|
{
|
2008-12-15 13:02:29 +00:00
|
|
|
GtkWidget *widget;
|
2008-12-11 12:49:26 +00:00
|
|
|
|
|
|
|
if (entry->widget_type == G_TYPE_NONE)
|
|
|
|
continue;
|
|
|
|
|
2008-12-15 13:02:29 +00:00
|
|
|
if (entry->widget_type == GTK_TYPE_RADIO_BUTTON)
|
2008-12-11 12:49:26 +00:00
|
|
|
{
|
2008-12-15 13:02:29 +00:00
|
|
|
handle_radio_buttons(owner, entry->fields, entry->setting, action);
|
|
|
|
continue;
|
2008-12-11 12:49:26 +00:00
|
|
|
}
|
2008-12-15 13:02:29 +00:00
|
|
|
|
|
|
|
widget = get_widget(owner, entry->widget_id);
|
|
|
|
if (!widget)
|
2008-12-11 12:49:26 +00:00
|
|
|
{
|
|
|
|
g_warning("Unknown widget for %s::%s in %s!", group->name, entry->key_name,
|
|
|
|
G_GNUC_FUNCTION);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-12-22 16:03:16 +00:00
|
|
|
/* note: can't use switch for GTK_TYPE macros */
|
2008-12-11 12:49:26 +00:00
|
|
|
if (entry->widget_type == GTK_TYPE_TOGGLE_BUTTON)
|
|
|
|
handle_toggle_button(widget, entry->setting, action);
|
2008-12-22 16:03:16 +00:00
|
|
|
else if (entry->widget_type == GTK_TYPE_SPIN_BUTTON)
|
|
|
|
handle_spin_button(widget, entry, action);
|
|
|
|
else if (entry->widget_type == GTK_TYPE_COMBO_BOX)
|
|
|
|
handle_combo_box(widget, entry, action);
|
2008-12-22 17:13:37 +00:00
|
|
|
else if (entry->widget_type == GTK_TYPE_COMBO_BOX_ENTRY)
|
|
|
|
handle_combo_box_entry(widget, entry, action);
|
|
|
|
else if (entry->widget_type == GTK_TYPE_ENTRY)
|
|
|
|
handle_entry(widget, entry, action);
|
2008-12-11 12:49:26 +00:00
|
|
|
else
|
|
|
|
g_warning("Unhandled type for %s::%s in %s!", group->name, entry->key_name,
|
|
|
|
G_GNUC_FUNCTION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @param owner If non-NULL, used to lookup widgets by name. */
|
|
|
|
void stash_group_display(GeanyPrefGroup *group, GtkWidget *owner)
|
|
|
|
{
|
|
|
|
pref_action(PREF_DISPLAY, group, owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void stash_group_update(GeanyPrefGroup *group, GtkWidget *owner)
|
|
|
|
{
|
|
|
|
pref_action(PREF_UPDATE, group, owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 13:01:50 +00:00
|
|
|
static GeanyPrefEntry *
|
|
|
|
add_widget_pref(GeanyPrefGroup *group, GType setting_type, gpointer setting,
|
|
|
|
const gchar *key_name, gpointer default_value,
|
|
|
|
GType widget_type, gpointer widget_id)
|
|
|
|
{
|
|
|
|
GeanyPrefEntry *entry =
|
|
|
|
add_pref(group, setting_type, setting, key_name, default_value);
|
|
|
|
|
|
|
|
entry->widget_type = widget_type;
|
|
|
|
entry->widget_id = widget_id;
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-15 13:02:29 +00:00
|
|
|
/* Used for GtkCheckButton or GtkToggleButton widgets.
|
|
|
|
* @see stash_group_add_radio_buttons(). */
|
2008-12-11 12:49:26 +00:00
|
|
|
void stash_group_add_toggle_button(GeanyPrefGroup *group, gboolean *setting,
|
|
|
|
const gchar *key_name, gboolean default_value, gpointer widget_id)
|
|
|
|
{
|
2008-12-22 13:01:50 +00:00
|
|
|
add_widget_pref(group, G_TYPE_BOOLEAN, setting, key_name, GINT_TO_POINTER(default_value),
|
|
|
|
GTK_TYPE_TOGGLE_BUTTON, widget_id);
|
2008-12-11 12:49:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-15 13:02:29 +00:00
|
|
|
/* @param ... pairs of widget_id, enum_id.
|
|
|
|
* Example (using widget lookup strings, but widget pointers can also work):
|
|
|
|
* @code
|
|
|
|
* enum {FOO, BAR};
|
|
|
|
* stash_group_add_radio_buttons(group, &which_one_setting, "which_one", BAR,
|
|
|
|
* "radio_foo", FOO, "radio_bar", BAR, NULL);
|
|
|
|
* @endcode */
|
|
|
|
void stash_group_add_radio_buttons(GeanyPrefGroup *group, gint *setting,
|
|
|
|
const gchar *key_name, gint default_value,
|
|
|
|
gpointer widget_id, gint enum_id, ...)
|
|
|
|
{
|
|
|
|
GeanyPrefEntry *entry =
|
2008-12-22 13:01:50 +00:00
|
|
|
add_widget_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value),
|
|
|
|
GTK_TYPE_RADIO_BUTTON, NULL);
|
2008-12-15 13:02:29 +00:00
|
|
|
va_list args;
|
|
|
|
gsize count = 1;
|
|
|
|
EnumWidget *item, *array;
|
|
|
|
|
|
|
|
/* count pairs of args */
|
|
|
|
va_start(args, enum_id);
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
gint dummy;
|
|
|
|
|
|
|
|
if (!va_arg(args, gpointer))
|
|
|
|
break;
|
|
|
|
dummy = va_arg(args, gint);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
array = g_new0(EnumWidget, count + 1);
|
|
|
|
entry->fields = array;
|
|
|
|
|
|
|
|
va_start(args, enum_id);
|
|
|
|
foreach_c_array(item, array, count)
|
|
|
|
{
|
|
|
|
if (item == array)
|
|
|
|
{
|
|
|
|
/* first element */
|
|
|
|
item->widget_id = widget_id;
|
|
|
|
item->enum_id = enum_id;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item->widget_id = va_arg(args, gpointer);
|
|
|
|
item->enum_id = va_arg(args, gint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 16:03:16 +00:00
|
|
|
void stash_group_add_spin_button_integer(GeanyPrefGroup *group, gint *setting,
|
|
|
|
const gchar *key_name, gint default_value, gpointer widget_id)
|
|
|
|
{
|
|
|
|
add_widget_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value),
|
|
|
|
GTK_TYPE_SPIN_BUTTON, widget_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 17:13:37 +00:00
|
|
|
/* @see stash_group_add_combo_box_entry(). */
|
2008-12-22 16:03:16 +00:00
|
|
|
void stash_group_add_combo_box(GeanyPrefGroup *group, gint *setting,
|
|
|
|
const gchar *key_name, gint default_value, gpointer widget_id)
|
|
|
|
{
|
|
|
|
add_widget_pref(group, G_TYPE_INT, setting, key_name, GINT_TO_POINTER(default_value),
|
|
|
|
GTK_TYPE_COMBO_BOX, widget_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-22 18:18:14 +00:00
|
|
|
/* We could maybe also have something like stash_group_add_combo_box_entry_with_menu()
|
|
|
|
* for the history list - or should that be stored as a separate setting? */
|
2008-12-22 17:13:37 +00:00
|
|
|
void stash_group_add_combo_box_entry(GeanyPrefGroup *group, gchar **setting,
|
|
|
|
const gchar *key_name, const gchar *default_value, gpointer widget_id)
|
|
|
|
{
|
|
|
|
add_widget_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value,
|
|
|
|
GTK_TYPE_COMBO_BOX_ENTRY, widget_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void stash_group_add_entry(GeanyPrefGroup *group, gchar **setting,
|
|
|
|
const gchar *key_name, const gchar *default_value, gpointer widget_id)
|
|
|
|
{
|
|
|
|
add_widget_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value,
|
|
|
|
GTK_TYPE_ENTRY, widget_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|