commit 31e4386c12e6fc14706858d0900c9da29d6e3fe1 Author: Paul Richardson aka phantomjinx <p.g.richard...@phantomjinx.co.uk> Date: Tue Apr 20 22:31:34 2010 +0100
updates and tweaks for latest anjuta * More updates to anjuta-app to sync with 2.28 * Add custom cleanup function for shutdown of the app * client server setup initialised in gp_itdb.c libgtkpod/gtkpod_app_iface.c | 10 ++- libgtkpod/gtkpod_app_iface.h | 2 + plugins/helloworld/helloworld.plugin | 1 - plugins/helloworld/plugin.c | 2 +- plugins/playlist_display/plugin.c | 2 +- src/anjuta-about.c | 3 +- src/anjuta-action-callbacks.c | 4 +- src/anjuta-app.c | 201 ++++++++++++++++++++++++---------- src/anjuta-app.h | 2 - src/display_itdb.c | 4 + src/gtkpod.c | 4 + src/misc.c | 45 ++++++++- src/misc.h | 2 + 13 files changed, 212 insertions(+), 70 deletions(-) --- diff --git a/libgtkpod/gtkpod_app_iface.c b/libgtkpod/gtkpod_app_iface.c index 4505c84..e0324bc 100644 --- a/libgtkpod/gtkpod_app_iface.c +++ b/libgtkpod/gtkpod_app_iface.c @@ -29,10 +29,11 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif +#include <glib/gi18n-lib.h> #include "gtkpod_app_iface.h" #include "gtkpod_app-marshallers.h" -#include <glib/gi18n-lib.h> +#include "misc.h" static void gtkpod_app_base_init(GtkPodAppInterface* klass) { static gboolean initialized = FALSE; @@ -104,6 +105,13 @@ gchar* gtkpod_get_glade_xml() { return GTKPOD_APP_GET_INTERFACE (gtkpod_app)->xml_file; } +/** + * clean up bits n pieces + */ +void gtkpod_cleanup_quit() { + gtkpod_shutdown(); +} + void gtkpod_statusbar_message(gchar* message, ...) { g_return_if_fail (GTKPOD_IS_APP(gtkpod_app)); gchar* msg; diff --git a/libgtkpod/gtkpod_app_iface.h b/libgtkpod/gtkpod_app_iface.h index 0c71b3f..c8d3299 100644 --- a/libgtkpod/gtkpod_app_iface.h +++ b/libgtkpod/gtkpod_app_iface.h @@ -133,6 +133,8 @@ void gp_init(GtkPodApp *window, int argc, char *argv[]); void gtkpod_app_set_glade_xml(gchar *xml_file); gchar* gtkpod_get_glade_xml(); +void gtkpod_cleanup_quit(); + void gtkpod_statusbar_message(gchar* message, ...); void gtkpod_statusbar_busy_push(); void gtkpod_statusbar_busy_pop(); diff --git a/plugins/helloworld/helloworld.plugin b/plugins/helloworld/helloworld.plugin index 3bcbd3b..f1cd4b7 100644 --- a/plugins/helloworld/helloworld.plugin +++ b/plugins/helloworld/helloworld.plugin @@ -1,5 +1,4 @@ [Anjuta Plugin] Location=helloworld:HelloWorldPlugin -Icon=helloworld.png Name=HelloWorld Plugin Description=A HelloWorld plugin for gtkpod diff --git a/plugins/helloworld/plugin.c b/plugins/helloworld/plugin.c index 9f293cf..8bd43a8 100644 --- a/plugins/helloworld/plugin.c +++ b/plugins/helloworld/plugin.c @@ -25,7 +25,7 @@ activate_plugin (AnjutaPlugin *plugin) /* Create hello plugin widget */ hello_plugin->widget = gtk_label_new ("Hello World Plugin!!"); - + gtk_widget_show_all(hello_plugin->widget); /* Add widget in Shell. Any number of widgets can be added */ anjuta_shell_add_widget (plugin->shell, hello_plugin->widget, "AnjutaHelloWorldPlugin", diff --git a/plugins/playlist_display/plugin.c b/plugins/playlist_display/plugin.c index 61d1dae..83bd95d 100644 --- a/plugins/playlist_display/plugin.c +++ b/plugins/playlist_display/plugin.c @@ -307,7 +307,7 @@ static gboolean activate_plugin(AnjutaPlugin *plugin) { gtk_container_add(GTK_CONTAINER (playlist_display_plugin->pl_window), GTK_WIDGET (playlist_display_plugin->playlist_view)); gtk_widget_show_all(playlist_display_plugin->pl_window); - anjuta_shell_add_widget(plugin->shell, playlist_display_plugin->pl_window, "PlaylistDisplayPlugin", "iPod Repositories", NULL, ANJUTA_SHELL_PLACEMENT_LEFT, NULL); + anjuta_shell_add_widget(plugin->shell, playlist_display_plugin->pl_window, "PlaylistDisplayPlugin", "iPod Repositories", GTK_STOCK_OPEN, ANJUTA_SHELL_PLACEMENT_LEFT, NULL); return TRUE; /* FALSE if activation failed */ } diff --git a/src/anjuta-about.c b/src/anjuta-about.c index 61a6933..479b09a 100644 --- a/src/anjuta-about.c +++ b/src/anjuta-about.c @@ -23,6 +23,7 @@ #endif #include <gtk/gtk.h> +#include <stdlib.h> #include <libanjuta/anjuta-plugin-manager.h> #include "anjuta-about.h" @@ -241,7 +242,7 @@ on_about_plugin_activate (GtkMenuItem *item, AnjutaPluginDescription *desc) authors_v = g_strsplit(authors, ",", -1); } dialog = gtk_about_dialog_new(); - gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), name); + gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), name); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION); if (license) gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), diff --git a/src/anjuta-action-callbacks.c b/src/anjuta-action-callbacks.c index 63410b3..f31c726 100644 --- a/src/anjuta-action-callbacks.c +++ b/src/anjuta-action-callbacks.c @@ -42,7 +42,7 @@ on_exit1_activate (GtkAction * action, AnjutaApp *app) { GdkEvent *event = gdk_event_new (GDK_DELETE); - event->any.window = g_object_ref (GTK_WIDGET(app)->window); + event->any.window = g_object_ref (gtk_widget_get_window (GTK_WIDGET(app))); event->any.send_event = TRUE; gtk_main_do_event (event); @@ -85,7 +85,7 @@ on_toolbar_view_toggled (GtkAction *action, AnjutaApp *app) { gtk_widget_hide (app->toolbar); } - anjuta_preferences_set_int (app->preferences, + anjuta_preferences_set_bool (app->preferences, "anjuta.toolbar.visible", status); } diff --git a/src/anjuta-app.c b/src/anjuta-app.c index 5713085..ab26b62 100644 --- a/src/anjuta-app.c +++ b/src/anjuta-app.c @@ -56,7 +56,7 @@ static void anjuta_app_layout_save(AnjutaApp *app, const gchar *layout_filename, static gpointer parent_class = NULL; static GtkToolbarStyle style = -1; -static gchar * uifile = NULL; +static gchar *uifile = NULL; static GHashTable *id_hash = NULL; @@ -80,6 +80,38 @@ void anjuta_set_ui_file_path(gchar * path) { uifile = path; } +static void menu_item_select_cb(GtkMenuItem *proxy, AnjutaApp *app) { + GtkAction *action; + char *message; + + action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(proxy)); + g_return_if_fail(action != NULL); + + g_object_get(G_OBJECT(action), "tooltip", &message, NULL); + if (message) { + anjuta_status_push(app->status, "%s", message); + g_free(message); + } +} + +static void menu_item_deselect_cb(GtkMenuItem *proxy, AnjutaApp *app) { + anjuta_status_pop(app->status); +} + +static void connect_proxy_cb(GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, AnjutaApp *app) { + if (GTK_IS_MENU_ITEM(proxy)) { + g_signal_connect(proxy, "select", G_CALLBACK(menu_item_select_cb), app); + g_signal_connect(proxy, "deselect", G_CALLBACK(menu_item_deselect_cb), app); + } +} + +static void disconnect_proxy_cb(GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, AnjutaApp *app) { + if (GTK_IS_MENU_ITEM(proxy)) { + g_signal_handlers_disconnect_by_func(proxy, G_CALLBACK(menu_item_select_cb), app); + g_signal_handlers_disconnect_by_func(proxy, G_CALLBACK(menu_item_deselect_cb), app); + } +} + static void on_toolbar_style_changed(AnjutaPreferences* prefs, const gchar* key, const gchar* tb_style, gpointer user_data) { AnjutaApp* app = ANJUTA_APP (user_data); @@ -329,8 +361,8 @@ static void anjuta_app_instance_init(AnjutaApp *app) { GtkWidget *main_box; GtkWidget *dockbar; GtkAction* action; - gchar* style; GList *plugins_dirs = NULL; + gchar * style; GdkGeometry size_hints = { 100, 100, 0, 0, 100, 100, 1, 1, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST }; @@ -376,7 +408,10 @@ static void anjuta_app_instance_init(AnjutaApp *app) { /* UI engine */ app->ui = anjuta_ui_new(); - g_object_add_weak_pointer(G_OBJECT (app->ui), (gpointer) &app->ui); + g_object_add_weak_pointer(G_OBJECT(app->ui), (gpointer) & app->ui); + /* show tooltips in the statusbar */ + g_signal_connect(app->ui, "connect_proxy", G_CALLBACK(connect_proxy_cb), app); + g_signal_connect(app->ui, "disconnect_proxy", G_CALLBACK(disconnect_proxy_cb), app); /* Plugin Manager */ g_printf("Prepending %s to plugin directories\n", get_plugin_dir()); @@ -456,6 +491,37 @@ static void anjuta_app_instance_init(AnjutaApp *app) { app->save_count = 0; } +/* + * GtkWindow catches keybindings for the menu items _before_ passing them to + * the focused widget. This is unfortunate and means that pressing ctrl+V + * in an entry on a panel ends up pasting text in the TextView. + * Here we override GtkWindow's handler to do the same things that it + * does, but in the opposite order and then we chain up to the grand + * parent handler, skipping gtk_window_key_press_event. + */ +static gboolean anjuta_app_key_press_event(GtkWidget *widget, GdkEventKey *event) { + static gpointer grand_parent_class = NULL; + GtkWindow *window = GTK_WINDOW(widget); + gboolean handled = FALSE; + + if (grand_parent_class == NULL) + grand_parent_class = g_type_class_peek_parent(parent_class); + + /* handle focus widget key events */ + if (!handled) + handled = gtk_window_propagate_key_event(window, event); + + /* handle mnemonics and accelerators */ + if (!handled) + handled = gtk_window_activate_key(window, event); + + /* Chain up, invokes binding set */ + if (!handled) + handled = GTK_WIDGET_CLASS(grand_parent_class)->key_press_event(widget, event); + + return handled; +} + static void anjuta_app_class_init(AnjutaAppClass *class) { GObjectClass *object_class; GtkWidgetClass *widget_class; @@ -463,8 +529,11 @@ static void anjuta_app_class_init(AnjutaAppClass *class) { parent_class = g_type_class_peek_parent(class); object_class = (GObjectClass*) class; widget_class = (GtkWidgetClass*) class; + object_class->finalize = anjuta_app_finalize; object_class->dispose = anjuta_app_dispose; + + widget_class->key_press_event = anjuta_app_key_press_event; } GtkWidget * @@ -566,19 +635,6 @@ void anjuta_app_layout_reset(AnjutaApp *app) { } void anjuta_app_install_preferences(AnjutaApp *app) { -// GladeXML *gxml; -// GtkWidget *notebook, *plugins; - - /* Create preferences page */ - // gxml = gtkpod_core_xml_new("gtkpod_preferences_window"); - // anjuta_preferences_add_page(app->preferences, gxml, "General", _("General"), ICON_FILE); - // notebook = glade_xml_get_widget(gxml, "General"); - // plugins = anjuta_plugin_manager_get_plugins_page(app->plugin_manager); - // gtk_widget_show(plugins); - // - // gtk_notebook_append_page(GTK_NOTEBOOK (notebook), plugins, gtk_label_new(_("Installed plugins"))); - // - // g_object_unref(gxml); GtkBuilder* builder = gtk_builder_new(); GError* error = NULL; GtkWidget *notebook, *shortcuts, *plugins, *remember_plugins; @@ -605,6 +661,8 @@ void anjuta_app_install_preferences(AnjutaApp *app) { gtk_notebook_append_page(GTK_NOTEBOOK (notebook), plugins, gtk_label_new(_("Installed plugins"))); gtk_notebook_append_page(GTK_NOTEBOOK (notebook), remember_plugins, gtk_label_new(_("Preferred plugins"))); + + g_object_unref(builder); } /* AnjutaShell Implementation */ @@ -742,34 +800,18 @@ static void on_widget_removed_from_hash(gpointer widget) { gtk_widget_destroy(menuitem); - g_object_set_data(G_OBJECT (widget), "dockitem", NULL); - g_object_set_data(G_OBJECT (widget), "menuitem", NULL); + g_object_set_data(G_OBJECT(widget), "dockitem", NULL); + g_object_set_data(G_OBJECT(widget), "menuitem", NULL); - g_signal_handlers_disconnect_by_func (G_OBJECT (widget), - G_CALLBACK (on_widget_destroy), app); - g_signal_handlers_disconnect_by_func (G_OBJECT (dockitem), - G_CALLBACK (on_widget_remove), app); + g_signal_handlers_disconnect_by_func(G_OBJECT(widget), G_CALLBACK(on_widget_destroy), app); + g_signal_handlers_disconnect_by_func(G_OBJECT(dockitem), G_CALLBACK(on_widget_remove), app); - g_object_unref(G_OBJECT (widget)); + g_object_unref(G_OBJECT(widget)); } -static void anjuta_app_add_widget_full(AnjutaShell *shell, GtkWidget *widget, const char *name, const char *title, const char *stock_id, AnjutaShellPlacement placement, gboolean locked, GError **error) { - AnjutaApp *app; - GtkWidget *item; +static void anjuta_app_setup_widget(AnjutaApp* app, const gchar* name, GtkWidget *widget, GtkWidget* item, const gchar* title, gboolean locked) { GtkCheckMenuItem* menuitem; - g_return_if_fail (ANJUTA_IS_APP (shell)); - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (name != NULL); - g_return_if_fail (title != NULL); - - app = ANJUTA_APP (shell); - - /* - anjuta_shell_add (shell, name, G_TYPE_FROM_INSTANCE (widget), - widget, NULL); - */ - /* Add the widget to hash */ if (app->widgets == NULL) { app->widgets = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, on_widget_removed_from_hash); @@ -777,6 +819,41 @@ static void anjuta_app_add_widget_full(AnjutaShell *shell, GtkWidget *widget, co g_hash_table_insert(app->widgets, g_strdup(name), widget); g_object_ref(widget); + /* Add toggle button for the widget */ + menuitem = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(title)); + gtk_widget_show(GTK_WIDGET(menuitem)); + gtk_check_menu_item_set_active(menuitem, TRUE); + gtk_menu_shell_append(GTK_MENU_SHELL(app->view_menu), GTK_WIDGET(menuitem)); + + if (locked) + g_object_set(G_OBJECT(menuitem), "visible", FALSE, NULL); + + g_object_set_data(G_OBJECT(widget), "app-object", app); + g_object_set_data(G_OBJECT(widget), "menuitem", menuitem); + g_object_set_data(G_OBJECT(widget), "dockitem", item); + + /* For toggling widget view on/off */ + g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(on_toggle_widget_view), item); + + /* + Watch for widget removal/destruction so that it could be + removed from widgets hash. + */ + g_signal_connect(G_OBJECT(item), "remove", G_CALLBACK(on_widget_remove), app); + g_signal_connect_after(G_OBJECT(widget), "destroy", G_CALLBACK(on_widget_destroy), app); +} + +static void anjuta_app_add_widget_full(AnjutaShell *shell, GtkWidget *widget, const char *name, const char *title, const char *stock_id, AnjutaShellPlacement placement, gboolean locked, GError **error) { + AnjutaApp *app; + GtkWidget *item; + + g_return_if_fail(ANJUTA_IS_APP (shell)); + g_return_if_fail(GTK_IS_WIDGET(widget)); + g_return_if_fail(name != NULL); + g_return_if_fail(title != NULL); + + app = ANJUTA_APP (shell); + /* Add the widget to dock */ if (stock_id == NULL) item = gdl_dock_item_new(name, title, GDL_DOCK_ITEM_BEH_NORMAL); @@ -797,33 +874,36 @@ static void anjuta_app_add_widget_full(AnjutaShell *shell, GtkWidget *widget, co if (locked) gdl_dock_item_set_default_position(GDL_DOCK_ITEM(item), GDL_DOCK_OBJECT(app->dock)); - gtk_widget_show(item); + anjuta_app_setup_widget(app, name, widget, item, title, locked); +} + +static void anjuta_app_add_widget_custom(AnjutaShell *shell, GtkWidget *widget, const char *name, const char *title, const char *stock_id, GtkWidget *label, AnjutaShellPlacement placement, GError **error) { + AnjutaApp *app; + GtkWidget *item; + GtkWidget *grip; - /* Add toggle button for the widget */ - menuitem = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_label (title)); - gtk_widget_show(GTK_WIDGET (menuitem)); - gtk_check_menu_item_set_active(menuitem, TRUE); - gtk_menu_append (GTK_MENU (app->view_menu), GTK_WIDGET (menuitem)); + g_return_if_fail(ANJUTA_IS_APP (shell)); + g_return_if_fail(GTK_IS_WIDGET(widget)); + g_return_if_fail(name != NULL); + g_return_if_fail(title != NULL); - if (locked) - g_object_set(G_OBJECT(menuitem), "visible", FALSE, NULL); + app = ANJUTA_APP (shell); - g_object_set_data(G_OBJECT (widget), "app-object", app); - g_object_set_data(G_OBJECT (widget), "menuitem", menuitem); - g_object_set_data(G_OBJECT (widget), "dockitem", item); + /* Add the widget to dock */ + /* Add the widget to dock */ + if (stock_id == NULL) + item = gdl_dock_item_new(name, title, GDL_DOCK_ITEM_BEH_NORMAL); + else + item = gdl_dock_item_new_with_stock(name, title, stock_id, GDL_DOCK_ITEM_BEH_NORMAL); - /* For toggling widget view on/off */ - g_signal_connect (G_OBJECT (menuitem), "toggled", - G_CALLBACK (on_toggle_widget_view), item); + gtk_container_add(GTK_CONTAINER(item), widget); + gdl_dock_add_item(GDL_DOCK(app->dock), GDL_DOCK_ITEM(item), placement); - /* - Watch for widget removal/destruction so that it could be - removed from widgets hash. - */ - g_signal_connect (G_OBJECT (item), "remove", - G_CALLBACK (on_widget_remove), app); - g_signal_connect_after (G_OBJECT (widget), "destroy", - G_CALLBACK (on_widget_destroy), app); + grip = gdl_dock_item_get_grip(GDL_DOCK_ITEM(item)); + + gdl_dock_item_grip_set_label(GDL_DOCK_ITEM_GRIP(grip), label); + + anjuta_app_setup_widget(app, name, widget, item, title, FALSE); } static void anjuta_app_remove_widget(AnjutaShell *shell, GtkWidget *widget, GError **error) { @@ -918,6 +998,7 @@ anjuta_app_get_profile_manager(AnjutaShell *shell, GError **error) { static void anjuta_shell_iface_init(AnjutaShellIface *iface) { iface->add_widget_full = anjuta_app_add_widget_full; + iface->add_widget_custom = anjuta_app_add_widget_custom; iface->remove_widget = anjuta_app_remove_widget; iface->present_widget = anjuta_app_present_widget; iface->add_value = anjuta_app_add_value; diff --git a/src/anjuta-app.h b/src/anjuta-app.h index 30a4ecc..f8f4d66 100644 --- a/src/anjuta-app.h +++ b/src/anjuta-app.h @@ -28,8 +28,6 @@ #include <libanjuta/anjuta-preferences.h> #include <libanjuta/anjuta-plugin-manager.h> #include <libanjuta/anjuta-profile-manager.h> -#include <libanjuta/anjuta-utils.h> -#include <libanjuta/anjuta-shell.h> #include "libgtkpod/gtkpod_app_iface.h" G_BEGIN_DECLS diff --git a/src/display_itdb.c b/src/display_itdb.c index ffd42e1..d1fe774 100644 --- a/src/display_itdb.c +++ b/src/display_itdb.c @@ -44,6 +44,7 @@ #include "prefs.h" #include "syncdir.h" #include "autodetection.h" +#include "clientserver.h" /* A struct containing a list with available iTunesDBs. A pointer to this struct is stored in gtkpod_app as itdbs_head */ @@ -826,6 +827,9 @@ void gp_init(GtkPodApp *single_app, int argc, char *argv[]) { /* Initiate autodetection */ autodetection_init(); + /* initiate client server */ + server_setup(); + /* Create tooltips */ main_tooltips = gtk_tooltips_new(); g_object_set_data(G_OBJECT (gtkpod_app), "main_tooltips", main_tooltips); diff --git a/src/gtkpod.c b/src/gtkpod.c index de4ba0f..2ac676a 100644 --- a/src/gtkpod.c +++ b/src/gtkpod.c @@ -26,6 +26,9 @@ | $Id$ */ +#include <libanjuta/anjuta-utils.h> +#include <libanjuta/anjuta-shell.h> + #include "gtkpod.h" #include "libgtkpod/directories.h" #include "libgtkpod/gtkpod_app_iface.h" @@ -255,6 +258,7 @@ static gboolean on_gtkpod_delete_event(GtkWidget *widget, GdkEvent *event, gpoin } static void on_gtkpod_destroy(GtkWidget * w, gpointer data) { + gtkpod_cleanup_quit(); gtk_widget_hide(w); gtk_main_quit(); } diff --git a/src/misc.c b/src/misc.c index 24a79cb..075c7d2 100644 --- a/src/misc.c +++ b/src/misc.c @@ -38,12 +38,14 @@ #include <sys/stat.h> #include <sys/wait.h> #include <unistd.h> +#include <glib/gi18n-lib.h> #include "charset.h" #include "clientserver.h" #include "misc.h" #include "prefs.h" #include "misc_track.h" -#include <glib/gi18n-lib.h> +#include "mp4file.h" +#include "file_convert.h" #define DEBUG_MISC 0 @@ -1815,3 +1817,44 @@ void delete_populate_settings(struct DeleteData *dd, gchar **label, gchar **titl } } +/** + * gtkpod_shutdown + * + * free memory, shutdown services and call gtk_main_quit () + */ +void gtkpod_shutdown () +{ + /* stop accepting requests for playcount updates */ + server_shutdown (); + + g_message("TODO - cleanup gphoto_window on shutdown"); + /* Change the windows back to track view to ensure the + * sorttab state is saved correctly/ + */ + //gphoto_change_to_photo_window (FALSE); + + /* shut down conversion infrastructure */ + file_convert_shutdown (); + + /* Save prefs */ + prefs_save (); + +/* FIXME: release memory in a clean way */ +#if 0 + remove_all_playlists (); /* first remove playlists, then tracks! + * (otherwise non-existing *tracks may + * be accessed) */ + remove_all_tracks (); +#endif + + prefs_shutdown (); + + xmlCleanupParser(); + xmlMemoryDump(); + + mp4_close(); + + call_script ("gtkpod.out", NULL); + gtk_main_quit (); +} + diff --git a/src/misc.h b/src/misc.h index 6010dba..1d1a415 100644 --- a/src/misc.h +++ b/src/misc.h @@ -224,4 +224,6 @@ void message_sb_no_itdb_selected (); void message_sb_no_playlist_selected (); void message_sb_no_tracks_selected (); +void gtkpod_shutdown (); + #endif ------------------------------------------------------------------------------ _______________________________________________ gtkpod-cvs2 mailing list gtkpod-cvs2@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2