From 2ab60ecb15ab1a7e30226563a15bbeec05dda54d Mon Sep 17 00:00:00 2001 From: javier Date: Sun, 7 Nov 2010 03:00:56 +0100 Subject: initial import --- presets.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 presets.c (limited to 'presets.c') diff --git a/presets.c b/presets.c new file mode 100644 index 0000000..f35901a --- /dev/null +++ b/presets.c @@ -0,0 +1,344 @@ +/* + * GPL 2 + */ + +#include +#include +#include + +#include "presets.h" + +G_DEFINE_TYPE(CFmPresets, cfm_presets, G_TYPE_OBJECT); + +#define CFM_PRESETS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CFM_TYPE_PRESETS, CFmPresetsPrivate)) + +#define GCONF_KEY_BUFFER_LEN 1024 +#define GCONF_PATH "/apps/maemo/cfmradio/presets" + +struct _CFmPresetsPrivate { + GConfClient *gconf; + gchar *name; + gchar *gconf_dir; + guint gconf_notify; + GHashTable *t; +}; + +enum { + PROP_0, + PROP_NAME, + PROP_LAST +}; + +enum { + SIGNAL_0, + SIGNAL_LAST +}; + +static GParamSpec *properties[PROP_LAST]; +static guint signals[SIGNAL_LAST]; + +static inline gfloat freq_to_float(gulong f) +{ + return f / 1000000.0; +} + +static inline gulong float_to_freq(gfloat f) +{ + return f * 1000000.0; +} + +static inline gfloat pointer_to_float(gpointer p) +{ + union { + gfloat f; + gpointer p; + } u; + u.p = p; + return u.f; +} + +static inline gpointer float_to_pointer(gfloat f) +{ + union { + gfloat f; + gpointer p; + } u; + u.f = f; + return u.p; +} + +static inline gpointer freq_to_pointer(gulong f) +{ + return float_to_pointer(freq_to_float(f)); +} + +static inline gulong pointer_to_freq(gpointer p) +{ + return float_to_freq(pointer_to_float(p)); +} + +static void func_gconf_entry_free(gpointer data, gpointer user_data) +{ + GConfEntry *entry = (GConfEntry*) data; + gconf_entry_free(entry); +} + +static void cfm_presets_load(CFmPresets *self) +{ + CFmPresetsPrivate *priv = self->priv; + + g_debug("Loading presets from %s\n", priv->gconf_dir); + + g_hash_table_remove_all(priv->t); + + GSList *i, *l = gconf_client_all_entries(priv->gconf, priv->gconf_dir, NULL); + for (i = l; i; i = g_slist_next(i)) { + GConfEntry *entry = (GConfEntry*) i->data; + const gchar *basename = g_basename(gconf_entry_get_key(entry)); + gfloat freq = g_ascii_strtod(basename, NULL); + const gchar *name = gconf_value_get_string(gconf_entry_get_value(entry)); + g_hash_table_insert(priv->t, float_to_pointer(freq), g_strdup(name)); + } + + g_slist_foreach(l, func_gconf_entry_free, NULL); + g_slist_free(l); +} + +static void cfm_presets_gconf_notify(GConfClient *gconf, guint cnxn_id, + GConfEntry *entry, gpointer user_data) +{ + CFmPresets *self = CFM_PRESETS(user_data); + CFmPresetsPrivate *priv = self->priv; + + if (!entry) { + return; + } + + const gchar *basename = g_basename(gconf_entry_get_key(entry)); + gfloat freq = g_ascii_strtod(basename, NULL); + GConfValue *value = gconf_entry_get_value(entry); + + if (value) { + const gchar *name = gconf_value_get_string(gconf_entry_get_value(entry)); + g_debug("Preset '%s' changed to '%s'\n", basename, name); + g_hash_table_insert(priv->t, float_to_pointer(freq), g_strdup(name)); + } else { + g_debug("Preset '%s' removed\n", basename); + g_hash_table_remove(priv->t, float_to_pointer(freq)); + } +} + +static void cfm_presets_set_property(GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + CFmPresets *self = CFM_PRESETS(object); + switch (property_id) { + case PROP_NAME: + g_free(self->priv->name); + self->priv->name = g_value_dup_string(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void cfm_presets_get_property(GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + CFmPresets *self = CFM_PRESETS(object); + switch (property_id) { + case PROP_NAME: + g_debug("Prop name is now set\n"); + g_value_set_string(value, self->priv->name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void cfm_presets_init(CFmPresets *self) +{ + CFmPresetsPrivate *priv; + + self->priv = priv = CFM_PRESETS_GET_PRIVATE(self); + + priv->gconf = gconf_client_get_default(); + priv->t = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); +} + +static GObject * cfm_presets_constructor(GType gtype, guint n_properties, + GObjectConstructParam *properties) +{ + GObject *object = G_OBJECT_CLASS(cfm_presets_parent_class)->constructor( + gtype, n_properties, properties); + CFmPresets *self = CFM_PRESETS(object); + CFmPresetsPrivate *priv = self->priv; + + priv->gconf_dir = g_strdup_printf("%s/%s", GCONF_PATH, priv->name); + + gconf_client_add_dir(priv->gconf, priv->gconf_dir, GCONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + priv->gconf_notify = gconf_client_notify_add(priv->gconf, priv->gconf_dir, + cfm_presets_gconf_notify, self, NULL, NULL); + + cfm_presets_load(self); + + return object; +} + +static void cfm_presets_dispose(GObject *object) +{ + CFmPresets *self = CFM_PRESETS(object); + CFmPresetsPrivate *priv = self->priv; + + if (priv->gconf && priv->gconf_notify) { + gconf_client_notify_remove(priv->gconf, priv->gconf_notify); + } + if (priv->gconf && priv->gconf_dir) { + gconf_client_remove_dir(priv->gconf, priv->gconf_dir, NULL); + } + if (priv->gconf_dir) { + g_free(priv->gconf_dir); + priv->gconf_dir = NULL; + } + if (priv->gconf) { + g_object_unref(priv->gconf); + priv->gconf = NULL; + } +} + +static void cfm_presets_finalize(GObject *object) +{ + CFmPresets *self = CFM_PRESETS(object); + CFmPresetsPrivate *priv = self->priv; + + g_hash_table_destroy(priv->t); + g_free(priv->name); +} + +static void cfm_presets_class_init(CFmPresetsClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + GParamSpec *param_spec; + + g_type_class_add_private (klass, sizeof(CFmPresetsPrivate)); + + gobject_class->constructor = cfm_presets_constructor; + gobject_class->set_property = cfm_presets_set_property; + gobject_class->get_property = cfm_presets_get_property; + gobject_class->dispose = cfm_presets_dispose; + gobject_class->finalize = cfm_presets_finalize; + + param_spec = g_param_spec_string("name", + "Preset set name", + "This is the name for this set of presets", + "default", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + properties[PROP_NAME] = param_spec; + g_object_class_install_property(gobject_class, PROP_NAME, param_spec); +} + +static gpointer cfm_presets_build_default(gpointer data) +{ + return g_object_new(CFM_TYPE_PRESETS, NULL); +} + +CFmPresets* cfm_presets_get_default() +{ + static GOnce once = G_ONCE_INIT; + g_once(&once, cfm_presets_build_default, NULL); + + return CFM_PRESETS(g_object_ref(G_OBJECT(once.retval))); +} + +CFmPresets* cfm_presets_get_for_name(const char * name) +{ + return g_object_new(CFM_TYPE_PRESETS, "name", name, NULL); +} + +void cfm_presets_set_preset(CFmPresets *self, gulong freq, const gchar *name) +{ + CFmPresetsPrivate *priv = self->priv; + GError *error = NULL; + gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; + gchar *key = g_strdup_printf("%s/%s", priv->gconf_dir, + g_ascii_formatd(buf, sizeof(buf), "%.1f", freq_to_float(freq))); + if (!gconf_client_set_string(priv->gconf, key, name, &error)) { + g_warning("Failed to store preset '%s' ('%s'): %s\n", key, name, + error->message); + } + g_free(key); +} + +void cfm_presets_remove_preset(CFmPresets *self, gulong freq) +{ + CFmPresetsPrivate *priv = self->priv; + GError *error = NULL; + gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; + gchar *key = g_strdup_printf("%s/%s", priv->gconf_dir, + g_ascii_formatd(buf, sizeof(buf), "%.1f", freq_to_float(freq))); + if (!gconf_client_unset(priv->gconf, key, &error)) { + g_warning("Failed to remove preset '%s': %s\n", key, error->message); + } + g_free(key); +} + +gboolean cfm_presets_is_preset(CFmPresets *self, gulong freq) +{ + CFmPresetsPrivate *priv = self->priv; + + return g_hash_table_lookup(priv->t, freq_to_pointer(freq)) ? TRUE : FALSE; +} + +const gchar * cfm_presets_get_preset(CFmPresets *self, gulong freq) +{ + CFmPresetsPrivate *priv = self->priv; + + gpointer found = g_hash_table_lookup(priv->t, freq_to_pointer(freq)); + if (found) { + return (const gchar *) found; + } else { + return NULL; + } + + return NULL; +} + +static void preset_to_list_store(gpointer key, gpointer value, gpointer user_data) +{ + GtkListStore *l = GTK_LIST_STORE(user_data); + GtkTreeIter iter; + + gulong freq = pointer_to_freq(key); + gtk_list_store_insert_with_values(l, &iter, 0, 0, freq, 1, value, -1); +} + +static gint compare_freq(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, + gpointer user_data) +{ + gulong freq_a, freq_b; + gtk_tree_model_get(model, a, 0, &freq_a, -1); + gtk_tree_model_get(model, b, 0, &freq_b, -1); + + if (freq_a > freq_b) return 1; + else if (freq_a < freq_b) return -1; + else return 0; +} + +GtkListStore* cfm_presets_get_all(CFmPresets *self) +{ + CFmPresetsPrivate *priv = self->priv; + GtkListStore *l = gtk_list_store_new(2, G_TYPE_ULONG, G_TYPE_STRING); + g_hash_table_foreach(priv->t, preset_to_list_store, l); + + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(l), 0, compare_freq, + NULL, NULL); + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(l), 0, + GTK_SORT_ASCENDING); + + return l; +} + -- cgit v1.2.3