X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Fnotify%2Fnotify.c;h=6b3be7cb4197e1b9a9099dc111e22fb3fef87670;hb=2d973ecfa0fae25f2b25fb824941b5ffba608c21;hp=35f0a9ed55bd60fbb329649724f4b7657688d50d;hpb=1fa9ce8dc234947c947a400b6d0f884afb75d11c;p=vlc diff --git a/modules/misc/notify/notify.c b/modules/misc/notify/notify.c index 35f0a9ed55..6b3be7cb41 100644 --- a/modules/misc/notify/notify.c +++ b/modules/misc/notify/notify.c @@ -1,7 +1,7 @@ /***************************************************************************** * notify.c : libnotify notification plugin ***************************************************************************** - * Copyright (C) 2006 the VideoLAN team + * Copyright (C) 2006-2009 the VideoLAN team * $Id$ * * Authors: Christophe Mutricy @@ -24,69 +24,101 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* malloc(), free() */ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include - -#include -#include -#include +#include +#include +#include +#include -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int Open ( vlc_object_t * ); -static void Close ( vlc_object_t * ); -static void Run ( intf_thread_t * ); - -static int ItemChange( vlc_object_t *, const char *, - vlc_value_t, vlc_value_t, void * ); -static int Notify( vlc_object_t *, const char * ); -#define MAX_LENGTH 256 +#include +#include /***************************************************************************** * Module descriptor ****************************************************************************/ - +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); #define APPLICATION_NAME "VLC media player" #define TIMEOUT_TEXT N_("Timeout (ms)") #define TIMEOUT_LONGTEXT N_("How long the notification will be displayed ") -vlc_module_begin(); - set_category( CAT_INTERFACE ); - set_subcategory( SUBCAT_INTERFACE_CONTROL ); - set_shortname( N_( "Notify" ) ); - set_description( _("LibNotify Notification Plugin") ); +vlc_module_begin () + set_category( CAT_INTERFACE ) + set_subcategory( SUBCAT_INTERFACE_CONTROL ) + set_shortname( N_( "Notify" ) ) + set_description( N_("LibNotify Notification Plugin") ) + + add_integer( "notify-timeout", 4000, NULL, + TIMEOUT_TEXT, TIMEOUT_LONGTEXT, true ) - add_integer( "notify-timeout", 4000,NULL, - TIMEOUT_TEXT, TIMEOUT_LONGTEXT, VLC_TRUE ); + set_capability( "interface", 0 ) + set_callbacks( Open, Close ) +vlc_module_end () - set_capability( "interface", 0 ); - set_callbacks( Open, Close ); -vlc_module_end(); + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int ItemChange( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); +static int Notify( vlc_object_t *, const char *, GdkPixbuf *, intf_thread_t * ); +#define MAX_LENGTH 256 + +struct intf_sys_t +{ + NotifyNotification *notification; + vlc_mutex_t lock; + bool b_has_actions; +}; /***************************************************************************** * Open: initialize and create stuff *****************************************************************************/ static int Open( vlc_object_t *p_this ) { - intf_thread_t *p_intf = (intf_thread_t *)p_this; - playlist_t *p_playlist; + intf_thread_t *p_intf = (intf_thread_t *)p_this; + intf_sys_t *p_sys = malloc( sizeof( *p_sys ) ); + + if( !p_sys ) + return VLC_ENOMEM; if( !notify_init( APPLICATION_NAME ) ) { + free( p_sys ); msg_Err( p_intf, "can't find notification daemon" ); return VLC_EGENERIC; } + p_intf->p_sys = p_sys; - p_playlist = pl_Yield( p_intf ); - var_AddCallback( p_playlist, "playlist-current", ItemChange, p_intf ); + vlc_mutex_init( &p_sys->lock ); + p_sys->notification = NULL; + p_sys->b_has_actions = false; + + GList *p_caps = notify_get_server_caps (); + if( p_caps ) + { + for( GList *c = p_caps; c != NULL; c = c->next ) + { + if( !strcmp( (char*)c->data, "actions" ) ) + { + p_sys->b_has_actions = true; + break; + } + } + g_list_foreach( p_caps, (GFunc)g_free, NULL ); + g_list_free( p_caps ); + } + + /* */ + playlist_t *p_playlist = pl_Hold( p_intf ); + var_AddCallback( p_playlist, "item-current", ItemChange, p_intf ); pl_Release( p_intf ); - p_intf->pf_run = Run; return VLC_SUCCESS; } @@ -95,19 +127,23 @@ static int Open( vlc_object_t *p_this ) *****************************************************************************/ static void Close( vlc_object_t *p_this ) { - playlist_t *p_playlist = pl_Yield( p_intf ); - var_DelCallback( p_playlist, "playlist-current", ItemChange, p_this ); - pl_Release( p_intf ); + intf_thread_t *p_intf = ( intf_thread_t* ) p_this; + intf_sys_t *p_sys = p_intf->p_sys; - notify_uninit(); -} + playlist_t *p_playlist = pl_Hold( p_this ); + var_DelCallback( p_playlist, "item-current", ItemChange, p_this ); + pl_Release( p_this ); -/***************************************************************************** - * Run - *****************************************************************************/ -static void Run( intf_thread_t *p_this ) -{ - msleep( 10*INTF_IDLE_SLEEP ); + if( p_sys->notification ) + { + GError *p_error = NULL; + notify_notification_close( p_sys->notification, &p_error ); + g_object_unref( p_sys->notification ); + } + + vlc_mutex_destroy( &p_sys->lock ); + free( p_sys ); + notify_uninit(); } /***************************************************************************** @@ -116,58 +152,184 @@ static void Run( intf_thread_t *p_this ) static int ItemChange( vlc_object_t *p_this, const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *param ) { - char psz_tmp[MAX_LENGTH]; - playlist_t *p_playlist; - char *psz_title = NULL; - char *psz_artist = NULL; - char *psz_album = NULL; - input_thread_t *p_input=NULL; - playlist_t * p_playlist = pl_Yield( p_this ); - - p_input = p_playlist->p_input; - vlc_object_release( p_playlist ); + VLC_UNUSED(psz_var); VLC_UNUSED(oldval); VLC_UNUSED(newval); + char psz_tmp[MAX_LENGTH]; + char psz_notify[MAX_LENGTH]; + char *psz_title = NULL; + char *psz_artist = NULL; + char *psz_album = NULL; + char *psz_arturl = NULL; + input_thread_t *p_input = playlist_CurrentInput( + (playlist_t*) p_this ); + intf_thread_t *p_intf = param; + intf_sys_t *p_sys = p_intf->p_sys; - if( !p_input ) return VLC_SUCCESS; - vlc_object_yield( p_input ); + if( !p_input ) + return VLC_SUCCESS; - if( p_input->b_dead || !p_input->input.p_item->psz_name ) + if( p_input->b_dead ) { /* Not playing anything ... */ vlc_object_release( p_input ); return VLC_SUCCESS; } + /* Wait a tad so the meta has been fetched + * FIXME that's awfully wrong */ + msleep( 1000*4 ); + /* Playing something ... */ - psz_artist = p_input->input.p_item->p_meta->psz_artist ? - strdup( p_input->input.p_item->p_meta->psz_artist ) : - strdup( _("no artist") ); - psz_album = p_input->input.p_item->p_meta->psz_album ? - strdup( p_input->input.p_item->p_meta->psz_album ) : - strdup( _("no album") ); - psz_title = strdup( p_input->input.p_item->psz_name ); - if( psz_title == NULL ) psz_title = strdup( N_("(no title)") ); - snprintf( psz_tmp, MAX_LENGTH, "%s\n%s - %s", - psz_title, psz_artist, psz_album ); + input_item_t *p_input_item = input_GetItem( p_input ); + psz_artist = input_item_GetArtist( p_input_item ); + psz_album = input_item_GetAlbum( p_input_item ); + psz_title = input_item_GetTitleFbName( p_input_item ); + + if( EMPTY_STR( psz_title ) ) + { /* Not enough metadata ... */ + free( psz_title ); + free( psz_artist ); + free( psz_album ); + vlc_object_release( p_input ); + return VLC_SUCCESS; + } + if( EMPTY_STR( psz_artist ) ) + { + free( psz_artist ); + psz_artist = NULL; + } + if( EMPTY_STR( psz_album ) ) + { + free( psz_album ); + psz_album = NULL; + } + + if( psz_artist && psz_album ) + snprintf( psz_tmp, MAX_LENGTH, "%s\n%s\n[%s]", + psz_title, psz_artist, psz_album ); + else if( psz_artist ) + snprintf( psz_tmp, MAX_LENGTH, "%s\n%s", + psz_title, psz_artist ); + else + snprintf( psz_tmp, MAX_LENGTH, "%s", psz_title ); + free( psz_title ); free( psz_artist ); free( psz_album ); - Notify( p_this, psz_tmp ); - + GdkPixbuf *pix = NULL; + psz_arturl = input_item_GetArtURL( p_input_item ); vlc_object_release( p_input ); + + if( psz_arturl && !strncmp( psz_arturl, "file://", 7 ) && + strlen( psz_arturl ) > 7 ) + { /* scale the art to show it in notify popup */ + GError *p_error = NULL; + pix = gdk_pixbuf_new_from_file_at_scale( &psz_arturl[7], + 72, 72, TRUE, &p_error ); + free( psz_arturl ); + } + else /* else we show state-of-the art logo */ + { + GError *p_error = NULL; + char *psz_pixbuf; + if( asprintf( &psz_pixbuf, "%s/vlc48x48.png", config_GetDataDir() ) >= 0 ) + { + pix = gdk_pixbuf_new_from_file( psz_pixbuf, &p_error ); + free( psz_pixbuf ); + } + } + + /* we need to replace '&' with '&' because '&' is a keyword of + * notification-daemon parser */ + const int i_len = strlen( psz_tmp ); + int i_notify = 0; + for( int i = 0; i < i_len && i_notify < ( MAX_LENGTH - 5 ); i++ ) + { /* we use MAX_LENGTH - 5 because if the last char of psz_tmp is '&' + * we will need 5 more characters: 'amp;\0' . + * however that's unlikely to happen because the last char is '\0' */ + if( psz_tmp[i] != '&' ) + { + psz_notify[i_notify] = psz_tmp[i]; + } + else + { + snprintf( &psz_notify[i_notify], 6, "&" ); + i_notify += 4; + } + i_notify++; + } + psz_notify[i_notify] = '\0'; + + vlc_mutex_lock( &p_sys->lock ); + + Notify( p_this, psz_notify, pix, p_intf ); + + vlc_mutex_unlock( &p_sys->lock ); + return VLC_SUCCESS; } -static int Notify( vlc_object_t *p_this, const char *psz_temp ) +static void Next( NotifyNotification *notification, gchar *psz, gpointer p ) +{ /* libnotify callback, called when the "Next" button is pressed */ + vlc_object_t *p_object = (vlc_object_t*)p; + + VLC_UNUSED(psz); + notify_notification_close( notification, NULL ); + playlist_t *p_playlist = pl_Hold( p_object ); + playlist_Next( p_playlist ); + pl_Release( p_object ); +} + +static void Prev( NotifyNotification *notification, gchar *psz, gpointer p ) +{ /* libnotify callback, called when the "Previous" button is pressed */ + vlc_object_t *p_object = (vlc_object_t*)p; + + VLC_UNUSED(psz); + notify_notification_close( notification, NULL ); + playlist_t *p_playlist = pl_Hold( p_object ); + playlist_Prev( p_playlist ); + pl_Release( p_object ); +} + +static int Notify( vlc_object_t *p_this, const char *psz_temp, GdkPixbuf *pix, + intf_thread_t *p_intf ) { + intf_sys_t *p_sys = p_intf->p_sys; + NotifyNotification * notification; + + /* Close previous notification if still active */ + if( p_sys->notification ) + { + GError *p_error = NULL; + notify_notification_close( p_sys->notification, &p_error ); + g_object_unref( p_sys->notification ); + } + notification = notify_notification_new( _("Now Playing"), - psz_temp, - DATA_PATH "/vlc128x128.png",NULL); + psz_temp, NULL, NULL ); notify_notification_set_timeout( notification, config_GetInt(p_this, "notify-timeout") ); notify_notification_set_urgency( notification, NOTIFY_URGENCY_LOW ); + if( pix ) + { + notify_notification_set_icon_from_pixbuf( notification, pix ); + gdk_pixbuf_unref( pix ); + } + + /* Adds previous and next buttons in the notification if actions are supported. */ + if( p_sys->b_has_actions ) + { + notify_notification_add_action( notification, "previous", _("Previous"), Prev, + (gpointer*)p_intf, NULL ); + notify_notification_add_action( notification, "next", _("Next"), Next, + (gpointer*)p_intf, NULL ); + } + notify_notification_show( notification, NULL); + + /* Stores the notification to be able to close it */ + p_sys->notification = notification; return VLC_SUCCESS; }