summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--cfmradio.c73
-rw-r--r--debian/changelog19
-rw-r--r--debian/control7
-rwxr-xr-xdebian/rules4
-rw-r--r--po/cfmradio.pot16
-rw-r--r--po/es.po16
-rw-r--r--preset_list.c44
-rw-r--r--preset_list.h6
-rw-r--r--presets.c187
-rw-r--r--presets.h6
-rw-r--r--radio.c9
-rw-r--r--radio.h8
-rw-r--r--radio_routing.h18
-rw-r--r--tuner.h2
-rw-r--r--types.c5
-rw-r--r--types.h9
17 files changed, 300 insertions, 135 deletions
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 <maemo@javispedro.com> 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 <maemo@javispedro.com> Fri, 21 Jan 2011 18:56:25 +0100
+
+cfmradio (0.3) unstable; urgency=low
+
+ * Testing audio routing (currently ifdef'd out).
+
+ -- Javier S. Pedro <maemo@javispedro.com> 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 <maemo@javispedro.com>\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 <pulse/xmalloc.h>
#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 <glib-object.h>
@@ -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 <glib.h>
+
+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 <glib-object.h>
#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 <glib-object.h>
@@ -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 */