Mercurial > audlegacy-plugins
view src/notify/notify.c @ 62:4a352dd2a91c trunk
[svn] - be a little smarter about this
author | nenolod |
---|---|
date | Sat, 30 Sep 2006 21:40:46 -0700 |
parents | 3da1b8942b8b |
children |
line wrap: on
line source
/* * 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 ); }