Mercurial > audlegacy-plugins
diff src/notify/notify.c @ 12:3da1b8942b8b trunk
[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 03:14:20 -0700 |
parents | src/General/notify/notify.c@088092a52fea |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/notify/notify.c Mon Sep 18 03:14:20 2006 -0700 @@ -0,0 +1,346 @@ +/* + * libnotify plugin for audacious 1.1+ + * http://nenolod.net/code/audacious-notify + * + * See `COPYING' in the directory root for license details. + */ +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <string.h> + +#include <libnotify/notify.h> +#include "audacious/plugin.h" +#include "audacious/playlist.h" +#include "audacious/input.h" +#include "audacious/configdb.h" + +#include "config.h" + +static void init(void); +static void cleanup(void); +static void configure_gui(void); +static void configure_load(void); +static void configure_save(void); +static gboolean watchdog_func(gpointer unused); +static gint timeout_tag = 0; + +static gint notify_playlist_pos = -1; +static gchar *previous_title = NULL; +static gboolean was_playing = FALSE; + +typedef struct +{ + gint notif_timeout; + gboolean notif_neverexpire; + gboolean notif_skipnf; +} +audcfg_t; + +static audcfg_t audcfg = { 5000 , FALSE , TRUE }; + +/* our API. */ +static void do_notification(gchar *summary, gchar *message, gchar *icon_uri); + +GeneralPlugin notify_gp = +{ + NULL, /* handle */ + NULL, /* filename */ + -1, /* xmms_session */ + NULL, /* Description */ + init, + NULL, + configure_gui, + cleanup +}; + +GeneralPlugin *get_gplugin_info(void) +{ + notify_gp.description = g_strdup_printf(_("libnotify Plugin %s"), PACKAGE_VERSION); + return ¬ify_gp; +} + +static void init(void) +{ + /* load configuration */ + configure_load(); + + /* Initialise libnotify */ + notify_init(PACKAGE); + + /* + TODO: I assume 100 means 100ms checking interval? Why not 200? + It would be twice as efficient and the user shouldn't notice any difference. + */ + timeout_tag = g_timeout_add(100, watchdog_func, NULL); +} + +static void cleanup(void) +{ + if ( timeout_tag > 0 ) + { + g_source_remove(timeout_tag); + timeout_tag = 0; + } + + if (previous_title != NULL) + { + g_free(previous_title); + previous_title = NULL; + } + + /* Uninitialise libnotify */ + if ( notify_is_initted() == TRUE ) + notify_uninit(); +} + +static gboolean watchdog_func(gpointer unused) +{ + gint pos = playlist_get_position(); + gchar *title = playlist_get_songtitle(pos); + + /* + Trigger a notice if a song is now playing and one of the following is true: + 1. it has a different title from the last time this ran + 2. there is no title but it's a different playlist position + 3. the player was stopped the last time this ran + (listed in the order they are checked) + + FIXME: The same song twice in a row will only get announced once. + Proposed Remedy: Add a check for playback progress. + */ + if (ip_data.playing && + ((title != NULL && previous_title != NULL && + g_strcasecmp(title, previous_title)) || + (title == NULL && pos != notify_playlist_pos) || (! was_playing))) + { + gchar *tmpbuf, *filename, *songtitle; + TitleInput *tuple; + + tuple = playlist_get_tuple(pos); + + if (tuple == NULL) + return TRUE; + + if (tuple->performer || tuple->album_name || tuple->track_name) { + filename = playlist_get_filename(pos); + + tmpbuf = g_markup_printf_escaped("<b>%s</b>\n<i>%s</i>\n%s", + (tuple->performer ? tuple->performer : ( audcfg.notif_skipnf == FALSE ? _("Unknown Artist") : "" )), + (tuple->album_name ? tuple->album_name : ( audcfg.notif_skipnf == FALSE ? _("Unknown Album") : "" )), + (tuple->track_name ? + tuple->track_name : + (filename ? + (strrchr(filename, '/') ? (strrchr(filename, '/') + 1) : filename) : + _("Unknown Track") + ) + ) + ); + } else { + songtitle = playlist_get_songtitle(pos); + + tmpbuf = g_markup_printf_escaped("%s", (songtitle ? songtitle : _("Unknown Track"))); + } + + do_notification("Audacious", tmpbuf, DATA_DIR "/pixmaps/audacious.png"); + g_free(tmpbuf); + } + + notify_playlist_pos = pos; + + if (previous_title != NULL) + { + g_free(previous_title); + previous_title = NULL; + } + + previous_title = g_strdup(title); + was_playing = ip_data.playing; + + return TRUE; +} + +static void do_notification(gchar *summary, gchar *message, gchar *icon_uri) +{ + NotifyNotification *n; + gint ret; + + n = notify_notification_new(summary, + message, + NULL, NULL); + + /* make sure we have a notify object before continuing, + * for paranoia's sake anyhow. -nenolod + */ + if (n == NULL) + return; + + if ( audcfg.notif_neverexpire == FALSE ) + notify_notification_set_timeout(n, audcfg.notif_timeout); + else + notify_notification_set_timeout(n, NOTIFY_EXPIRES_NEVER); + + if (icon_uri != NULL) + { + GdkPixbuf *gp = gdk_pixbuf_new_from_file(icon_uri, NULL); + + if (gp != NULL) + { + notify_notification_set_icon_from_pixbuf(n, GDK_PIXBUF(gp)); + g_object_unref(G_OBJECT(gp)); + } + } + + ret = notify_notification_show(n, NULL); + +#if 0 + /* rainy day: handle this condition below -nenolod */ + if (ret == 0) + { + /* do something */ + } +#endif + + g_object_unref(G_OBJECT(n)); +} + + +/* ABOUTBOX - TODO -> complete me with credits info! + +static void about_gui(void) +{ + static GtkWidget *aboutwin = NULL; + gchar *aboutstr; + + if ( aboutwin != NULL ) + return; + + aboutstr = g_strdup_printf( _("Audacious libnotify Plugin\n\n...") ); + aboutwin = xmms_show_message( _("About libnotify Plugin"), _(aboutstr), _("Ok"), FALSE, NULL, NULL); + g_free( aboutstr ); + g_signal_connect( G_OBJECT(aboutwin) , "destroy", G_CALLBACK(gtk_widget_destroyed), &aboutwin ); +} +*/ + + +/* CONFIGURATION */ + +static void configure_load(void) +{ + ConfigDb *db; + + db = bmp_cfg_db_open(); + bmp_cfg_db_get_bool(db, "libnotify", "notif_skipnf", &audcfg.notif_skipnf); + bmp_cfg_db_get_int(db, "libnotify", "notif_timeout", &audcfg.notif_timeout); + bmp_cfg_db_get_bool(db, "libnotify", "notif_neverexpire", &audcfg.notif_neverexpire); + bmp_cfg_db_close(db); +} + +static void configure_save(void) +{ + ConfigDb *db = bmp_cfg_db_open(); + bmp_cfg_db_set_bool(db, "libnotify", "notif_skipnf", audcfg.notif_skipnf); + bmp_cfg_db_set_int(db, "libnotify", "notif_timeout", audcfg.notif_timeout); + bmp_cfg_db_set_bool(db, "libnotify", "notif_neverexpire", audcfg.notif_neverexpire); + bmp_cfg_db_close(db); +} + + +static void configure_ev_notiftimeout_toggle( GtkToggleButton *togglebt , gpointer hbox ) +{ + gtk_widget_set_sensitive( GTK_WIDGET(hbox) , !gtk_toggle_button_get_active( togglebt ) ); +} + +static void configure_ev_notifskipnf_commit( gpointer togglebt ) +{ + audcfg.notif_skipnf = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(togglebt) ); +} + +static void configure_ev_notiftimeout_commit( gpointer spinbt ) +{ + audcfg.notif_timeout = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(spinbt) ); +} + +static void configure_ev_notifexpire_commit( gpointer togglebt ) +{ + audcfg.notif_neverexpire = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(togglebt) ); +} + +static void configure_ev_bok( gpointer configwin ) +{ + configure_save(); + gtk_widget_destroy( GTK_WIDGET(configwin) ); +} + +static void configure_gui(void) +{ + static GtkWidget *configwin = NULL; + GtkWidget *configwin_vbox; + GtkWidget *notif_info_frame, *notif_info_vbox, *notif_info_skipnf_cbt; + GtkWidget *notif_timeout_frame, *notif_timeout_hbox, *notif_timeout_vbox; + GtkWidget *notif_timeout_spinbt, *notif_timeout_cbt; + GtkWidget *hbuttonbox, *button_ok, *button_cancel; + + if ( configwin != NULL ) + return; + + configwin = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(configwin), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_title( GTK_WINDOW(configwin), _("libnotify plugin") ); + gtk_container_set_border_width( GTK_CONTAINER(configwin), 10 ); + g_signal_connect( G_OBJECT(configwin) , "destroy" , G_CALLBACK(gtk_widget_destroyed) , &configwin ); + configwin_vbox = gtk_vbox_new( FALSE , 6 ); + gtk_container_add( GTK_CONTAINER(configwin) , configwin_vbox ); + button_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); + + /* notification info */ + notif_info_frame = gtk_frame_new( _("Notification details") ); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , notif_info_frame , TRUE , TRUE , 0 ); + notif_info_vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(notif_info_vbox), 4 ); + gtk_container_add( GTK_CONTAINER(notif_info_frame) , notif_info_vbox ); + notif_info_skipnf_cbt = gtk_check_button_new_with_label( _("Skip empty fields") ); + g_signal_connect_swapped( G_OBJECT(button_ok) , "clicked" , + G_CALLBACK(configure_ev_notifskipnf_commit) , notif_info_skipnf_cbt ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(notif_info_skipnf_cbt) , audcfg.notif_skipnf ); + gtk_box_pack_start( GTK_BOX(notif_info_vbox) , notif_info_skipnf_cbt , FALSE , FALSE , 0 ); + + /* notification timeout */ + notif_timeout_frame = gtk_frame_new( _("Notification timeout") ); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , notif_timeout_frame , TRUE , TRUE , 0 ); + notif_timeout_vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(notif_timeout_vbox), 4 ); + gtk_container_add( GTK_CONTAINER(notif_timeout_frame) , notif_timeout_vbox ); + notif_timeout_hbox = gtk_hbox_new( FALSE , 2 ); + notif_timeout_spinbt = gtk_spin_button_new_with_range( 1 , 20000 , 100 ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(notif_timeout_spinbt) , (gdouble)audcfg.notif_timeout ); + g_signal_connect_swapped( G_OBJECT(button_ok) , "clicked" , + G_CALLBACK(configure_ev_notiftimeout_commit) , notif_timeout_spinbt ); + gtk_box_pack_start( GTK_BOX(notif_timeout_hbox) , + gtk_label_new( _("Expire time:") ) , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(notif_timeout_hbox) , notif_timeout_spinbt , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(notif_timeout_hbox) , + gtk_label_new( _("ms") ) , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(notif_timeout_vbox) , notif_timeout_hbox , FALSE , FALSE , 0 ); + notif_timeout_cbt = gtk_check_button_new_with_label( _("Notification never expires") ); + g_signal_connect( G_OBJECT(notif_timeout_cbt) , "toggled" , + G_CALLBACK(configure_ev_notiftimeout_toggle) , notif_timeout_hbox ); + g_signal_connect_swapped( G_OBJECT(button_ok) , "clicked" , + G_CALLBACK(configure_ev_notifexpire_commit) , notif_timeout_cbt ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(notif_timeout_cbt) , audcfg.notif_neverexpire ); + gtk_box_pack_start( GTK_BOX(notif_timeout_vbox) , notif_timeout_cbt , FALSE , FALSE , 0 ); + + /* buttons */ + hbuttonbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(hbuttonbox) , GTK_BUTTONBOX_END ); + button_cancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL ); + g_signal_connect_swapped( G_OBJECT(button_cancel) , "clicked" , + G_CALLBACK(gtk_widget_destroy) , configwin ); + gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_cancel ); + g_signal_connect_swapped( G_OBJECT(button_ok) , "clicked" , + G_CALLBACK(configure_ev_bok) , configwin ); + gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_ok ); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , hbuttonbox , FALSE , FALSE , 0 ); + + gtk_widget_show_all( configwin ); +}