diff options
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | cfmradio.c | 73 | ||||
| -rw-r--r-- | debian/changelog | 19 | ||||
| -rw-r--r-- | debian/control | 7 | ||||
| -rwxr-xr-x | debian/rules | 4 | ||||
| -rw-r--r-- | po/cfmradio.pot | 16 | ||||
| -rw-r--r-- | po/es.po | 16 | ||||
| -rw-r--r-- | preset_list.c | 44 | ||||
| -rw-r--r-- | preset_list.h | 6 | ||||
| -rw-r--r-- | presets.c | 187 | ||||
| -rw-r--r-- | presets.h | 6 | ||||
| -rw-r--r-- | radio.c | 9 | ||||
| -rw-r--r-- | radio.h | 8 | ||||
| -rw-r--r-- | radio_routing.h | 18 | ||||
| -rw-r--r-- | tuner.h | 2 | ||||
| -rw-r--r-- | types.c | 5 | ||||
| -rw-r--r-- | types.h | 9 | 
17 files changed, 300 insertions, 135 deletions
| @@ -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 @@ -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 "" @@ -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_ */ @@ -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; -} - @@ -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__ */ @@ -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) @@ -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 + @@ -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__ */ @@ -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); @@ -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 */ | 
