X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Fnotify%2Fnotify.c;h=9069e6d0705c0dcad03a104ea06b255c7ec6e2b6;hb=07329b0a5a64b6fd3d9c7c078fc08f3148be81ba;hp=362c56274690dbb664d1d8aabd852cb37478d1e8;hpb=2be706031a5458206001911335e3388315772768;p=vlc diff --git a/modules/misc/notify/notify.c b/modules/misc/notify/notify.c index 362c562746..9069e6d070 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,85 +24,99 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include -#include - -#include +#include +#include #include #include -#include +#include + +#include +#include /***************************************************************************** - * Local prototypes - *****************************************************************************/ + * 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( N_("LibNotify Notification Plugin") ) + + add_integer( "notify-timeout", 4000, NULL, + TIMEOUT_TEXT, TIMEOUT_LONGTEXT, true ) + + 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 *, 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; }; -/***************************************************************************** - * Module descriptor - ****************************************************************************/ - -#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( _( "Notify" ) ); - set_description( _("LibNotify Notification Plugin") ); - - add_integer( "notify-timeout", 4000,NULL, - TIMEOUT_TEXT, TIMEOUT_LONGTEXT, VLC_TRUE ); - - set_capability( "interface", 0 ); - set_callbacks( Open, Close ); -vlc_module_end(); - /***************************************************************************** * 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_sys_t *p_sys = malloc( sizeof( intf_sys_t ) ); - + intf_sys_t *p_sys = malloc( sizeof( *p_sys ) ); + if( !p_sys ) - { - msg_Err( p_intf, "Out of memory" ); return VLC_ENOMEM; - } if( !notify_init( APPLICATION_NAME ) ) { + free( p_sys ); msg_Err( p_intf, "can't find notification daemon" ); return VLC_EGENERIC; } - - vlc_mutex_init( p_this, &p_sys->lock ); - p_intf->p_sys = p_sys; - p_intf->p_sys->notification = NULL; + vlc_mutex_init( &p_sys->lock ); + p_sys->notification = NULL; + p_sys->b_has_actions = false; - p_playlist = pl_Yield( p_intf ); - var_AddCallback( p_playlist, "playlist-current", ItemChange, p_intf ); - pl_Release( p_intf ); + 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 ); + } + + /* */ + var_AddCallback( pl_Get( p_intf ), "item-current", ItemChange, p_intf ); return VLC_SUCCESS; } @@ -115,9 +129,14 @@ static void Close( vlc_object_t *p_this ) intf_thread_t *p_intf = ( intf_thread_t* ) p_this; intf_sys_t *p_sys = p_intf->p_sys; - playlist_t *p_playlist = pl_Yield( p_this ); - var_DelCallback( p_playlist, "playlist-current", ItemChange, p_this ); - pl_Release( p_this ); + var_DelCallback( pl_Get( p_this ), "item-current", ItemChange, p_this ); + + 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 ); @@ -130,21 +149,19 @@ static void Close( vlc_object_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]; - char *psz_title = NULL; - char *psz_artist = NULL; - char *psz_album = NULL; - char *psz_arturl = NULL; - input_thread_t *p_input = NULL; - playlist_t * p_playlist = pl_Yield( p_this ); - intf_thread_t *p_intf = ( intf_thread_t* ) param; - intf_sys_t *p_sys = p_intf->p_sys; - - p_input = p_playlist->p_input; - pl_Release( p_playlist ); - - if( !p_input ) return VLC_SUCCESS; - vlc_object_yield( p_input ); + VLC_UNUSED(psz_var); VLC_UNUSED(oldval); VLC_UNUSED(newval); + char psz_tmp[MAX_LENGTH]; + char psz_notify[MAX_LENGTH]; + char *psz_title; + char *psz_artist; + char *psz_album; + char *psz_arturl; + 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; if( p_input->b_dead ) { @@ -153,70 +170,142 @@ static int ItemChange( vlc_object_t *p_this, const char *psz_var, return VLC_SUCCESS; } + /* Wait a tad so the meta has been fetched + * FIXME that's awfully wrong */ + msleep( 10000 ); + /* Playing something ... */ - psz_artist = input_item_GetArtist( input_GetItem( p_input ) ); - if( psz_artist == NULL ) psz_artist = strdup( _("no artist") ); - psz_album = input_item_GetAlbum( input_GetItem( p_input ) ) ; - if( psz_album == NULL ) psz_album = strdup( _("no album") ); - psz_title = input_item_GetTitle( input_GetItem( p_input ) ); - if( psz_title == NULL ) - psz_title = input_item_GetName( input_GetItem( p_input ) ); - if( psz_title == NULL ) - { /* Not enough metadata ... */ - free( psz_artist ); - free( psz_album ); + input_item_t *p_input_item = input_GetItem( p_input ); + psz_title = input_item_GetTitleFbName( p_input_item ); + + /* We need at least a title */ + if( EMPTY_STR( psz_title ) ) + { + free( psz_title ); vlc_object_release( p_input ); return VLC_SUCCESS; } - vlc_object_release( p_input ); + psz_artist = input_item_GetArtist( p_input_item ); + psz_album = input_item_GetAlbum( p_input_item ); + + if( !EMPTY_STR( psz_artist ) ) + { + if( !EMPTY_STR( psz_album ) ) + snprintf( psz_tmp, MAX_LENGTH, "%s\n%s\n[%s]", + psz_title, psz_artist, psz_album ); + else + snprintf( psz_tmp, MAX_LENGTH, "%s\n%s", + psz_title, psz_artist ); + } + else + snprintf( psz_tmp, MAX_LENGTH, "%s", psz_title ); - 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 ); free( psz_title ); free( psz_artist ); free( psz_album ); GdkPixbuf *pix = NULL; - GError *p_error = NULL; + psz_arturl = input_item_GetArtURL( p_input_item ); + vlc_object_release( p_input ); - psz_arturl = input_item_GetArtURL( input_GetItem( p_input ) ); - if( psz_arturl && !strncmp( psz_arturl, "file://", 7 ) && - strlen( psz_arturl ) > 7 ) - { /* scale the art to show it in notify popup */ - gboolean b = TRUE; - pix = gdk_pixbuf_new_from_file_at_scale( - (psz_arturl + 7), 72, 72, b, &p_error ); + if( psz_arturl ) + { + char *psz = make_path( psz_arturl ); free( psz_arturl ); + psz_arturl = psz; + } + + if( psz_arturl ) + { /* scale the art to show it in notify popup */ + GError *p_error = NULL; + pix = gdk_pixbuf_new_from_file_at_scale( psz_arturl, + 72, 72, TRUE, &p_error ); } else /* else we show state-of-the art logo */ - pix = gdk_pixbuf_new_from_file( DATA_PATH "/vlc48x48.png", &p_error ); + { + GError *p_error = NULL; + char *psz_pixbuf; + char *psz_data = config_GetDataDir( p_this ); + if( asprintf( &psz_pixbuf, "%s/vlc48x48.png", psz_data ) >= 0 ) + { + pix = gdk_pixbuf_new_from_file( psz_pixbuf, &p_error ); + free( psz_pixbuf ); + } + free( psz_data ); + } + + free( psz_arturl ); + + /* 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 + { + strcpy( &psz_notify[i_notify], "&" ); + i_notify += 4; + } + i_notify++; + } + psz_notify[i_notify] = '\0'; vlc_mutex_lock( &p_sys->lock ); - Notify( p_this, psz_tmp, pix, param ); + Notify( p_this, psz_notify, pix, p_intf ); vlc_mutex_unlock( &p_sys->lock ); return VLC_SUCCESS; } +/* libnotify callback, called when the "Next" button is pressed */ +static void Next( NotifyNotification *notification, gchar *psz, gpointer p ) +{ + vlc_object_t *p_object = (vlc_object_t*)p; + + VLC_UNUSED(psz); + notify_notification_close( notification, NULL ); + playlist_Next( pl_Get( p_object ) ); +} + +/* libnotify callback, called when the "Previous" button is pressed */ +static void Prev( NotifyNotification *notification, gchar *psz, gpointer p ) +{ + vlc_object_t *p_object = (vlc_object_t*)p; + + VLC_UNUSED(psz); + notify_notification_close( notification, NULL ); + playlist_Prev( pl_Get( p_object ) ); +} + static int Notify( vlc_object_t *p_this, const char *psz_temp, GdkPixbuf *pix, - void *param ) + intf_thread_t *p_intf ) { - intf_thread_t *p_intf = (intf_thread_t *)param; + intf_sys_t *p_sys = p_intf->p_sys; + NotifyNotification * notification; - GError *p_error = NULL; /* Close previous notification if still active */ - if( p_intf->p_sys->notification ) - notify_notification_close( p_intf->p_sys->notification, &p_error ); + 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, NULL, NULL); + psz_temp, NULL, NULL ); notify_notification_set_timeout( notification, - config_GetInt(p_this, "notify-timeout") ); + var_InheritInteger(p_this, "notify-timeout") ); notify_notification_set_urgency( notification, NOTIFY_URGENCY_LOW ); if( pix ) { @@ -224,10 +313,19 @@ static int Notify( vlc_object_t *p_this, const char *psz_temp, GdkPixbuf *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_intf->p_sys->notification = notification; + p_sys->notification = notification; return VLC_SUCCESS; }