From bf65330d3ef0e57d0bf2d4c6171c77038695b771 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Sat, 22 Jan 2011 04:03:32 +0100 Subject: lots of UI work --- Makefile | 6 +- cfmradio.c | 73 ++++++++++++++++++---- debian/changelog | 19 ++++++ debian/control | 7 ++- debian/rules | 4 ++ po/cfmradio.pot | 16 ++--- po/es.po | 16 ++--- preset_list.c | 44 +++++++++++-- preset_list.h | 6 +- presets.c | 187 ++++++++++++++++++++++++++++++++----------------------- presets.h | 6 +- radio.c | 9 +-- radio.h | 8 +-- radio_routing.h | 18 ++++++ tuner.h | 2 +- types.c | 5 +- types.h | 9 +-- 17 files changed, 300 insertions(+), 135 deletions(-) create mode 100644 radio_routing.h diff --git a/Makefile b/Makefile index f60915e..f7c222e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS?=-Os -g -Wall +CFLAGS?=-O0 -g -Wall LDFLAGS?=-Wl,--as-needed LOCALEDIR?=/usr/share/locale @@ -8,11 +8,11 @@ GETTEXT_CFLAGS:=-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" -DLOCALEDIR=\"$(LOCALED PKGCONFIG_PKGS:=libosso hildon-1 alsa libpulse-mainloop-glib dbus-glib-1 gconf-2.0 PKGCONFIG_CFLAGS:=$(shell pkg-config $(PKGCONFIG_PKGS) --cflags) PKGCONFIG_LIBS:=$(shell pkg-config $(PKGCONFIG_PKGS) --libs) -LAUNCHER_CFLAGS:=$(shell pkg-config maemo-launcher-app --cflags) +LAUNCHER_CFLAGS:=$(shell pkg-config maemo-launcher-app --cflags) -fvisibility=hidden LAUNCHER_LDFLAGS:=$(shell pkg-config maemo-launcher-app --libs) MISC_CFLAGS:=-std=gnu99 -DG_LOG_DOMAIN=\"CFmRadio\" -SRCS:=cfmradio.c radio.c types.c tuner.c rds.c \ +SRCS:=cfmradio.c radio.c radio_routing.c types.c tuner.c rds.c \ presets.c preset_list.c preset_renderer.c OBJS:=$(SRCS:.c=.o) POT:=po/$(GETTEXT_PACKAGE).pot diff --git a/cfmradio.c b/cfmradio.c index 5431e6f..90084b8 100644 --- a/cfmradio.c +++ b/cfmradio.c @@ -8,6 +8,9 @@ #include "tuner.h" #include "types.h" +// TODO +#include "radio_routing.h" + #define SCAN_LOCK_TIME 1 #define SCAN_INCREMENT 100000 @@ -32,6 +35,9 @@ static guint rds_timer; static guint scan_timer; static gulong scan_prev_freq, scan_max; +/* The only symbol externally visible (for maemo-launcher). */ +int main(int argc, char *argv[]) __attribute__((visibility("default"))); + static void cancel_scan(); static void print_freq(gulong freq) @@ -50,7 +56,7 @@ static void print_rds() gulong freq; gchar *rds_ps, *rds_rt; gchar *markup; - const gchar *preset; + gchar *preset; g_object_get(G_OBJECT(radio), "frequency", &freq, "rds-ps", &rds_ps, "rds-rt", &rds_rt, NULL); @@ -60,13 +66,15 @@ static void print_rds() gtk_label_set_markup(ps_label, markup); g_free(markup); - gtk_label_set_text(rt_label, g_strstrip(rds_rt)); preset = cfm_presets_get_preset(presets, freq); - if (preset && preset[0] == '\0') { - /* If the preset exists but has no name, give it one. */ - cfm_presets_set_preset(presets, freq, rds_ps); + if (preset) { + if (strlen(preset) == 0 && strlen(rds_ps) > 1) { + /* If the preset exists but has no name, give it one. */ + cfm_presets_set_preset(presets, freq, rds_ps); + } + g_free(preset); } g_free(rds_ps); @@ -142,7 +150,10 @@ static gboolean rds_timer_cb(gpointer data) static void presets_clicked(GtkButton *button, gpointer user_data) { - cfm_preset_list_show_for(preset_list, presets); + gulong freq; + g_object_get(G_OBJECT(radio), "frequency", &freq, NULL); + g_object_set(G_OBJECT(preset_list), "frequency", freq, NULL); + cfm_preset_list_show(preset_list); } static void preset_frequency_cb(GObject *object, GParamSpec *psec, gpointer user_data) @@ -151,7 +162,7 @@ static void preset_frequency_cb(GObject *object, GParamSpec *psec, gpointer user cancel_scan(); g_object_get(G_OBJECT(preset_list), "frequency", &freq, NULL); g_object_set(G_OBJECT(radio), "frequency", freq, NULL); - gtk_widget_hide(GTK_WIDGET(preset_list)); + cfm_preset_list_hide(preset_list); print_freq(freq); } @@ -191,13 +202,13 @@ static gboolean scan_step(gpointer data) guint signal; g_object_get(G_OBJECT(radio), "frequency", &freq, "signal", &signal, NULL); - g_print("Autoscan %f Mhz: %f %%\n", freq / 1000000.0f, signal / 655.36f), + g_debug("Autoscan %.2f MHz: %.0f %%", freq / 1000000.0f, signal / 655.36f), g_object_set(G_OBJECT(tuner), "frequency", freq, NULL); print_freq(freq); if (signal > (65536 / 3)) { /* Signal > 33% : Create / Update preset */ - /* TODO: Rounding */ + g_debug(" -> Found station at %lu Hz", freq); if (!cfm_presets_is_preset(presets, freq)) { cfm_presets_set_preset(presets, freq, ""); } @@ -248,6 +259,27 @@ static void cancel_scan(void) end_scan(); } +static void speaker_clicked(void) +{ + cfm_radio_route_audio_to_speakers(); +} + +static void bypass_clicked(void) +{ + g_object_set(G_OBJECT(radio), "output", CFM_RADIO_OUTPUT_MUTE, NULL); +usleep(1000); + cfm_radio_route_audio_to_headphones(); +usleep(1000); + cfm_radio_route_audio_bypass(); +} + +static void reset_clicked(void) +{ + cfm_radio_route_audio_reset(); +usleep(1000); + g_object_set(G_OBJECT(radio), "output", CFM_RADIO_OUTPUT_SYSTEM, NULL); +} + static void build_main_window() { GtkBox *box; @@ -281,6 +313,21 @@ static void build_main_window() G_CALLBACK(remove_preset_clicked), NULL); hildon_app_menu_append(menu, GTK_BUTTON(menu_button)); +#if ADV_AUDIO_ROUTING + menu_button = gtk_button_new_with_label("Speaker output"); + g_signal_connect_after(G_OBJECT(menu_button), "clicked", + G_CALLBACK(speaker_clicked), NULL); + hildon_app_menu_append(menu, GTK_BUTTON(menu_button)); + menu_button = gtk_button_new_with_label("Analog bypass"); + g_signal_connect_after(G_OBJECT(menu_button), "clicked", + G_CALLBACK(bypass_clicked), NULL); + hildon_app_menu_append(menu, GTK_BUTTON(menu_button)); + menu_button = gtk_button_new_with_label("Reset audio to HP"); + g_signal_connect_after(G_OBJECT(menu_button), "clicked", + G_CALLBACK(reset_clicked), NULL); + hildon_app_menu_append(menu, GTK_BUTTON(menu_button)); +#endif + gtk_widget_show_all(GTK_WIDGET(menu)); gtk_widget_hide(GTK_WIDGET(stop_scan_button)); @@ -370,10 +417,14 @@ int main(int argc, char *argv[]) gtk_widget_show_all(GTK_WIDGET(main_window)); preset_list = cfm_preset_list_new(); - g_signal_connect(G_OBJECT(preset_list), "delete-event", + GtkTreeModel *model; + g_object_get(G_OBJECT(presets), "model", &model, NULL); + g_object_set(G_OBJECT(preset_list), "model", model, NULL); + g_signal_connect(G_OBJECT(preset_list), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); - g_signal_connect(G_OBJECT(preset_list), "notify::frequency", + g_signal_connect(G_OBJECT(preset_list), "preset-selected", G_CALLBACK(preset_frequency_cb), NULL); + g_object_unref(model); g_object_set(G_OBJECT(radio), "output", CFM_RADIO_OUTPUT_SYSTEM, NULL); diff --git a/debian/changelog b/debian/changelog index 17d9c0e..fdd0fdb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,22 @@ +cfmradio (0.3.2) unstable; urgency=low + + * Playing with making presets a GtkTreeModel. + + -- Javier S. Pedro Sat, 22 Jan 2011 04:01:30 +0100 + +cfmradio (0.3.1) unstable; urgency=low + + * Fixing bug while scrolling in the presets dialog. + * Reduced binary size by removing most public symbols. + + -- Javier S. Pedro Fri, 21 Jan 2011 18:56:25 +0100 + +cfmradio (0.3) unstable; urgency=low + + * Testing audio routing (currently ifdef'd out). + + -- Javier S. Pedro Fri, 21 Jan 2011 16:22:44 +0100 + cfmradio (0.2) unstable; urgency=low * Implementing presets. diff --git a/debian/control b/debian/control index 21bb97e..144234d 100644 --- a/debian/control +++ b/debian/control @@ -10,10 +10,11 @@ Package: cfmradio Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, n900-fmrx-enabler Description: FM radio player - Listen to FM radio from your N900 + A FM radio player written in plain C using Hildon with a minimalist interface. XB-Description-es_ES: Reproductor de radio FM - Escucha radio FM desde tu N900 -XSBC-Maemo-Display-Name: Radio + Un reproductor de radio FM escrito en C usando Hildon con una interfaz + minimalista. +XSBC-Maemo-Display-Name: C FM Radio XB-Maemo-Icon-26: iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAA AAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oK diff --git a/debian/rules b/debian/rules index ef96488..cbfdb57 100755 --- a/debian/rules +++ b/debian/rules @@ -10,6 +10,7 @@ #export DH_VERBOSE=1 CFLAGS = -Wall -g +LDFLAGS = -Wl,--as-needed ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 @@ -17,6 +18,9 @@ else CFLAGS += -Os endif +export CFLAGS +export LDFLAGS + build: build-stamp build-stamp: diff --git a/po/cfmradio.pot b/po/cfmradio.pot index 45ee09e..6542bf2 100644 --- a/po/cfmradio.pot +++ b/po/cfmradio.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: CFmRadio\n" "Report-Msgid-Bugs-To: maemo@javispedro.com\n" -"POT-Creation-Date: 2011-01-14 20:52+0100\n" +"POT-Creation-Date: 2011-01-22 03:25+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,30 +16,30 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: cfmradio.c:248 +#: cfmradio.c:288 msgid "Radio" msgstr "" -#: cfmradio.c:255 +#: cfmradio.c:295 msgid "Presets…" msgstr "" -#: cfmradio.c:259 +#: cfmradio.c:299 msgid "Scan for presets" msgstr "" -#: cfmradio.c:263 +#: cfmradio.c:303 msgid "Stop scanning" msgstr "" -#: cfmradio.c:267 +#: cfmradio.c:307 msgid "Set preset" msgstr "" -#: cfmradio.c:271 +#: cfmradio.c:311 msgid "Remove preset" msgstr "" -#: preset_list.c:112 +#: preset_list.c:138 msgid "Presets" msgstr "" diff --git a/po/es.po b/po/es.po index 40d59c8..8cf7bd5 100644 --- a/po/es.po +++ b/po/es.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: CFmRadio\n" "Report-Msgid-Bugs-To: maemo@javispedro.com\n" -"POT-Creation-Date: 2011-01-14 20:52+0100\n" +"POT-Creation-Date: 2011-01-22 03:25+0100\n" "PO-Revision-Date: 2011-01-14 20:40+0100\n" "Last-Translator: Javier \n" "Language-Team: Spanish\n" @@ -18,30 +18,30 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: cfmradio.c:248 +#: cfmradio.c:288 msgid "Radio" msgstr "Radio" -#: cfmradio.c:255 +#: cfmradio.c:295 msgid "Presets…" msgstr "Emisoras…" -#: cfmradio.c:259 +#: cfmradio.c:299 msgid "Scan for presets" msgstr "Buscar emisoras" -#: cfmradio.c:263 +#: cfmradio.c:303 msgid "Stop scanning" msgstr "Detener búsqueda" -#: cfmradio.c:267 +#: cfmradio.c:307 msgid "Set preset" msgstr "Añadir emisora" -#: cfmradio.c:271 +#: cfmradio.c:311 msgid "Remove preset" msgstr "Quitar emisora" -#: preset_list.c:112 +#: preset_list.c:138 msgid "Presets" msgstr "Emisoras" diff --git a/preset_list.c b/preset_list.c index 5621f9f..c82eb64 100644 --- a/preset_list.c +++ b/preset_list.c @@ -20,6 +20,7 @@ struct _CFmPresetListPrivate { HildonTouchSelector *sel; HildonTouchSelectorColumn *col; GtkCellRenderer *renderer; + gint munge_selected_signal; }; enum { @@ -31,6 +32,7 @@ enum { enum { SIGNAL_0, + SIGNAL_PRESET_SELECTED, SIGNAL_LAST }; @@ -41,8 +43,18 @@ static void cfm_preset_list_selection_changed(HildonTouchSelector *selector, gint column, gpointer user_data) { CFmPresetList *self = CFM_PRESET_LIST(user_data); + CFmPresetListPrivate *priv = self->priv; g_object_notify(G_OBJECT(self), "frequency"); + + if (priv->munge_selected_signal) { + return; + } + if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(self))) { + return; + } + + g_signal_emit(G_OBJECT(self), signals[SIGNAL_PRESET_SELECTED], 0, NULL); } static void cfm_preset_list_set_property(GObject *object, guint property_id, @@ -54,6 +66,23 @@ static void cfm_preset_list_set_property(GObject *object, guint property_id, case PROP_MODEL: hildon_touch_selector_set_model(priv->sel, 0, g_value_get_object(value)); break; + case PROP_FREQUENCY: { + GtkTreeModel *model = hildon_touch_selector_get_model(priv->sel, 0); + GtkTreeIter iter; + gulong sel_freq = g_value_get_ulong(value); + if (!gtk_tree_model_get_iter_first(model, &iter)) return; + do { + gulong freq; + gtk_tree_model_get(model, &iter, 0, &freq, -1); + if (sel_freq == freq) { + priv->munge_selected_signal++; + hildon_touch_selector_select_iter(priv->sel, 0, &iter, FALSE); + priv->munge_selected_signal--; + return; + } + } while (gtk_tree_model_iter_next(model, &iter)); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -117,7 +146,7 @@ static void cfm_preset_list_init(CFmPresetList *self) priv->renderer = cfm_preset_renderer_new(); g_object_set(G_OBJECT(priv->renderer), "xpad", HILDON_MARGIN_DEFAULT, NULL); priv->col = hildon_touch_selector_append_column(priv->sel, model, - priv->renderer, "frequency", 0, "name", 1); + priv->renderer, "frequency", 0, "name", 1, NULL); hildon_touch_selector_column_set_text_column(priv->col, 0); gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(priv->sel)); @@ -154,6 +183,10 @@ static void cfm_preset_list_class_init(CFmPresetListClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_FREQUENCY] = param_spec; g_object_class_install_property(gobject_class, PROP_FREQUENCY, param_spec); + + signals[SIGNAL_PRESET_SELECTED] = g_signal_new("preset-selected", + G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } CFmPresetList* cfm_preset_list_new() @@ -161,10 +194,13 @@ CFmPresetList* cfm_preset_list_new() return g_object_new(CFM_TYPE_PRESET_LIST, NULL); } -void cfm_preset_list_show_for(CFmPresetList *self, CFmPresets *presets) +void cfm_preset_list_show(CFmPresetList *self) { - g_object_set(self, "model", cfm_presets_get_all(presets), NULL); - gtk_widget_show_all(GTK_WIDGET(self)); } +void cfm_preset_list_hide(CFmPresetList *self) +{ + gtk_widget_hide(GTK_WIDGET(self)); +} + diff --git a/preset_list.h b/preset_list.h index 9930242..8390d30 100644 --- a/preset_list.h +++ b/preset_list.h @@ -30,8 +30,10 @@ struct _CFmPresetListClass HildonStackableWindowClass parent; }; -GType cfm_preset_list_get_type (void); +GType cfm_preset_list_get_type(void) G_GNUC_CONST; CFmPresetList* cfm_preset_list_new(); -void cfm_preset_list_show_for(CFmPresetList *self, CFmPresets *presets); + +void cfm_preset_list_show(CFmPresetList *self); +void cfm_preset_list_hide(CFmPresetList *self); #endif /* _CFM_PRESET_LIST_H_ */ diff --git a/presets.c b/presets.c index 2f1f37b..f9d5c85 100644 --- a/presets.c +++ b/presets.c @@ -20,61 +20,64 @@ struct _CFmPresetsPrivate { gchar *name; gchar *gconf_dir; guint gconf_notify; + GtkListStore *l; GHashTable *t; }; enum { - PROP_0, - PROP_NAME, - PROP_LAST + COL_INVALID = -1, + COL_FREQUENCY = 0, + COL_NAME }; enum { - SIGNAL_0, - SIGNAL_LAST + PROP_0, + PROP_NAME, + PROP_MODEL, + PROP_LAST }; static GParamSpec *properties[PROP_LAST]; -static guint signals[SIGNAL_LAST]; -static inline gfloat freq_to_float(gulong f) +static inline gulong round_freq(gulong freq) +{ + const gulong round_to = 100000; /* 0.1 MHz */ + return ((freq + round_to / 2) / round_to) * round_to; +} + +static inline gulong ffreq_to_freq(gfloat ffreq) { - return f / 1000000.0; + return round_freq(ffreq * 1000000.0f); } -static inline gulong float_to_freq(gfloat f) +static inline gfloat freq_to_ffreq(gulong freq) { - return f * 1000000.0; + return freq / 1000000.0f; } -static inline gfloat pointer_to_float(gpointer p) +static inline gpointer freq_to_pointer(gulong freq) { - union { - gfloat f; - gpointer p; - } u; - u.p = p; - return u.f; + return GUINT_TO_POINTER(freq); } -static inline gpointer float_to_pointer(gfloat f) +static inline gulong pointer_to_freq(gpointer ptr) { - union { - gfloat f; - gpointer p; - } u; - u.f = f; - return u.p; + return GPOINTER_TO_UINT(ptr); } -static inline gpointer freq_to_pointer(gulong f) +static inline gpointer ffreq_to_pointer(gfloat ffreq) { - return float_to_pointer(freq_to_float(f)); + return freq_to_pointer(ffreq_to_freq(ffreq)); } -static inline gulong pointer_to_freq(gpointer p) +static inline gfloat pointer_to_ffreq(gpointer ptr) { - return float_to_freq(pointer_to_float(p)); + return freq_to_ffreq(pointer_to_freq(ptr)); +} + +static void destroy_iter(gpointer data) +{ + g_slice_free(GtkTreeIter, data); } static void func_gconf_entry_free(gpointer data, gpointer user_data) @@ -83,6 +86,18 @@ static void func_gconf_entry_free(gpointer data, gpointer user_data) gconf_entry_free(entry); } +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; +} + static void cfm_presets_load(CFmPresets *self) { CFmPresetsPrivate *priv = self->priv; @@ -95,9 +110,16 @@ static void cfm_presets_load(CFmPresets *self) 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); + gfloat ffreq = g_ascii_strtod(basename, NULL); + gulong freq = ffreq_to_freq(ffreq); 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)); + GtkTreeIter *iter = g_slice_new(GtkTreeIter); + gtk_list_store_insert_with_values(priv->l, iter, 0, + COL_FREQUENCY, freq, + COL_NAME, name, + COL_INVALID + ); + g_hash_table_insert(priv->t, freq_to_pointer(freq), iter); } g_slist_foreach(l, func_gconf_entry_free, NULL); @@ -115,16 +137,37 @@ static void cfm_presets_gconf_notify(GConfClient *gconf, guint cnxn_id, } const gchar *basename = g_basename(gconf_entry_get_key(entry)); - gfloat freq = g_ascii_strtod(basename, NULL); + gfloat ffreq = g_ascii_strtod(basename, NULL); + gulong freq = ffreq_to_freq(ffreq); + gpointer t_data = g_hash_table_lookup(priv->t, freq_to_pointer(freq)); 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)); + if (t_data) { + /* Modifying existing preset's name */ + GtkTreeIter *iter = (GtkTreeIter*)t_data; + g_debug("Preset '%s' changed to '%s'\n", basename, name); + gtk_list_store_set(priv->l, iter, COL_NAME, name, COL_INVALID); + } else { + GtkTreeIter *iter = g_slice_new(GtkTreeIter); + g_debug("Preset '%s' set to '%s'\n", basename, name); + gtk_list_store_insert_with_values(priv->l, iter, 0, + COL_FREQUENCY, freq, + COL_NAME, name, + COL_INVALID + ); + g_hash_table_insert(priv->t, freq_to_pointer(freq), iter); + } + } else { - g_debug("Preset '%s' removed\n", basename); - g_hash_table_remove(priv->t, float_to_pointer(freq)); + + if (t_data) { + GtkTreeIter *iter = (GtkTreeIter*)t_data; + g_debug("Preset '%s' removed\n", basename); + gtk_list_store_remove(priv->l, iter); + g_hash_table_remove(priv->t, freq_to_pointer(freq)); + } } } @@ -151,6 +194,9 @@ static void cfm_presets_get_property(GObject *object, guint property_id, case PROP_NAME: g_value_set_string(value, self->priv->name); break; + case PROP_MODEL: + g_value_set_object(value, self->priv->l); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -164,7 +210,8 @@ static void cfm_presets_init(CFmPresets *self) 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); + priv->t = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, destroy_iter); } static GObject * cfm_presets_constructor(GType gtype, guint n_properties, @@ -182,6 +229,12 @@ static GObject * cfm_presets_constructor(GType gtype, guint n_properties, priv->gconf_notify = gconf_client_notify_add(priv->gconf, priv->gconf_dir, cfm_presets_gconf_notify, self, NULL, NULL); + priv->l = gtk_list_store_new(2, G_TYPE_ULONG, G_TYPE_STRING); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(priv->l), 0, compare_freq, + NULL, NULL); + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->l), 0, + GTK_SORT_ASCENDING); + cfm_presets_load(self); return object; @@ -206,6 +259,10 @@ static void cfm_presets_dispose(GObject *object) g_object_unref(priv->gconf); priv->gconf = NULL; } + if (priv->l) { + g_object_unref(priv->l); + priv->l = NULL; + } } static void cfm_presets_finalize(GObject *object) @@ -238,6 +295,13 @@ static void cfm_presets_class_init(CFmPresetsClass *klass) G_PARAM_STATIC_STRINGS); properties[PROP_NAME] = param_spec; g_object_class_install_property(gobject_class, PROP_NAME, param_spec); + param_spec = g_param_spec_object("model", + "Preset list model", + "A model containing this set of presets", + GTK_TYPE_TREE_MODEL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_MODEL] = param_spec; + g_object_class_install_property(gobject_class, PROP_MODEL, param_spec); } static gpointer cfm_presets_build_default(gpointer data) @@ -264,7 +328,7 @@ void cfm_presets_set_preset(CFmPresets *self, gulong freq, const gchar *name) 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))); + g_ascii_formatd(buf, sizeof(buf), "%.1f", freq_to_ffreq(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); @@ -278,7 +342,7 @@ void cfm_presets_remove_preset(CFmPresets *self, gulong freq) 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))); + g_ascii_formatd(buf, sizeof(buf), "%.1f", freq_to_ffreq(freq))); if (!gconf_client_unset(priv->gconf, key, &error)) { g_warning("Failed to remove preset '%s': %s\n", key, error->message); } @@ -292,13 +356,17 @@ gboolean cfm_presets_is_preset(CFmPresets *self, gulong freq) return g_hash_table_lookup(priv->t, freq_to_pointer(freq)) ? TRUE : FALSE; } -const gchar * cfm_presets_get_preset(CFmPresets *self, gulong freq) +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; + gpointer t_data = g_hash_table_lookup(priv->t, freq_to_pointer(freq)); + if (t_data) { + GtkTreeIter *iter = (GtkTreeIter*) t_data; + gchar *name; + gtk_tree_model_get(GTK_TREE_MODEL(priv->l), iter, + COL_NAME, &name, COL_INVALID); + return name; } else { return NULL; } @@ -306,38 +374,3 @@ const gchar * cfm_presets_get_preset(CFmPresets *self, gulong freq) 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; -} - diff --git a/presets.h b/presets.h index 88c910d..fa73f1d 100644 --- a/presets.h +++ b/presets.h @@ -30,16 +30,14 @@ struct _CFmPresetsClass GObjectClass parent_class; }; -GType cfm_presets_get_type(void); +GType cfm_presets_get_type(void) G_GNUC_CONST; CFmPresets* cfm_presets_get_default(); CFmPresets* cfm_presets_get_for_name(const gchar *name); void cfm_presets_set_preset(CFmPresets *self, gulong freq, const gchar *name); void cfm_presets_remove_preset(CFmPresets *self, gulong freq); gboolean cfm_presets_is_preset(CFmPresets *self, gulong freq); -const gchar * cfm_presets_get_preset(CFmPresets *self, gulong freq); - -GtkListStore* cfm_presets_get_all(CFmPresets *self); +gchar* cfm_presets_get_preset(CFmPresets *self, gulong freq); #endif /* __CFM_PRESETS_H__ */ diff --git a/radio.c b/radio.c index 6b8048f..8070671 100644 --- a/radio.c +++ b/radio.c @@ -20,6 +20,7 @@ #include #include "radio.h" +#include "radio_routing.h" #include "types.h" #include "n900-fmrx-enabler.h" #include "rds.h" @@ -225,8 +226,8 @@ static void cfm_radio_init_tuner(CFmRadio *self, const gchar * device) TRUE : FALSE; if (priv->precise_tuner) { - priv->range_low = tuner.rangelow * 62.5f; - priv->range_high = tuner.rangehigh * 62.5f; + priv->range_low = tuner.rangelow * 62.5; + priv->range_high = tuner.rangehigh * 62.5; } else { priv->range_low = tuner.rangelow * 62500; priv->range_high = tuner.rangehigh * 62500; @@ -456,7 +457,7 @@ static void cfm_radio_set_frequency(CFmRadio *self, gulong freq) g_return_if_fail(priv->fd != -1); t_freq.tuner = 0; t_freq.type = V4L2_TUNER_RADIO; - t_freq.frequency = priv->precise_tuner ? freq / 62.5f : freq / 62500; + t_freq.frequency = priv->precise_tuner ? freq / 62.5 : freq / 62500; int res = ioctl(priv->fd, VIDIOC_S_FREQUENCY, &t_freq); g_warn_if_fail(res == 0); } @@ -469,7 +470,7 @@ static gulong cfm_radio_get_frequency(CFmRadio *self) t_freq.tuner = 0; int res = ioctl(priv->fd, VIDIOC_G_FREQUENCY, &t_freq); g_return_val_if_fail(res == 0, 0); - return priv->precise_tuner ? t_freq.frequency * 62.5f : t_freq.frequency * 62500; + return priv->precise_tuner ? t_freq.frequency * 62.5 : t_freq.frequency * 62500; } static guint cfm_radio_get_signal(CFmRadio *self) diff --git a/radio.h b/radio.h index a20477d..b68e20a 100644 --- a/radio.h +++ b/radio.h @@ -2,8 +2,8 @@ * GPL 2 */ -#ifndef __CFM_RADIO_H__ -#define __CFM_RADIO_H__ +#ifndef CFM_RADIO_H +#define CFM_RADIO_H #include @@ -29,11 +29,11 @@ struct _CFmRadioClass GObjectClass parent_class; }; -GType cfm_radio_get_type (void); +GType cfm_radio_get_type(void) G_GNUC_CONST; CFmRadio* cfm_radio_new(); void cfm_radio_seek_up(CFmRadio* radio); void cfm_radio_seek_down(CFmRadio* radio); -#endif /* __CFM_RADIO_H__ */ +#endif /* CFM_RADIO_H */ diff --git a/radio_routing.h b/radio_routing.h new file mode 100644 index 0000000..ee11366 --- /dev/null +++ b/radio_routing.h @@ -0,0 +1,18 @@ +/* + * GPL 2 + */ + +#ifndef CFM_RADIO_ROUTING_H +#define CFM_RADIO_ROUTING_H + +#include + +void cfm_radio_route_audio_to_headphones(); +void cfm_radio_route_audio_to_speakers(); + +void cfm_radio_route_audio_bypass(); + +void cfm_radio_route_audio_reset(); + +#endif + diff --git a/tuner.h b/tuner.h index c29825d..adabb41 100644 --- a/tuner.h +++ b/tuner.h @@ -29,7 +29,7 @@ struct _CFmTunerClass GtkDrawingAreaClass parent; }; -GType cfm_tuner_get_type (void); +GType cfm_tuner_get_type(void) G_GNUC_CONST; CFmTuner* cfm_tuner_new(); #endif /* __CFM_TUNER_H__ */ diff --git a/types.c b/types.c index 0bb63d3..47071a3 100644 --- a/types.c +++ b/types.c @@ -2,8 +2,7 @@ #include #include "types.h" -GType -cfm_radio_output_get_type(void) +GType cfm_radio_output_get_type(void) { static GType etype = 0; @@ -13,6 +12,8 @@ cfm_radio_output_get_type(void) { CFM_RADIO_OUTPUT_SYSTEM, "CFM_RADIO_OUTPUT_SYSTEM", "system" }, { CFM_RADIO_OUTPUT_SPEAKER, "CFM_RADIO_OUTPUT_SPEAKER", "speaker" }, { CFM_RADIO_OUTPUT_HEADPHONES, "CFM_RADIO_OUTPUT_HEADPHONES", "headphones" }, + { CFM_RADIO_OUTPUT_HEADPHONES_BYPASS, "CFM_RADIO_OUTPUT_HEADPHONES_BYPASS", + "headphones-bypass" }, { 0, NULL, NULL } }; etype = g_enum_register_static("CFmRadioOutput", values); diff --git a/types.h b/types.h index 8ecc837..709e47d 100644 --- a/types.h +++ b/types.h @@ -1,6 +1,6 @@ -#ifndef __CFMRADIO_TYPES_H__ -#define __CFMRADIO_TYPES_H__ +#ifndef CFM_TYPES_H +#define CFM_TYPES_H #include @@ -10,7 +10,8 @@ typedef enum { CFM_RADIO_OUTPUT_MUTE = 0, CFM_RADIO_OUTPUT_SYSTEM, CFM_RADIO_OUTPUT_SPEAKER, - CFM_RADIO_OUTPUT_HEADPHONES + CFM_RADIO_OUTPUT_HEADPHONES, + CFM_RADIO_OUTPUT_HEADPHONES_BYPASS } CFmRadioOutput; GType cfm_radio_output_get_type(void) G_GNUC_CONST; @@ -18,5 +19,5 @@ GType cfm_radio_output_get_type(void) G_GNUC_CONST; G_END_DECLS -#endif /*__CFMRADIO_TYPES_H__ */ +#endif /* CFM_TYPES_H */ -- cgit v1.2.3