notify.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:11k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * notify.c : libnotify notification plugin
  3.  *****************************************************************************
  4.  * Copyright (C) 2006-2009 the VideoLAN team
  5.  * $Id: 6fa084af1bfda1805226444c465b636ab616ad3c $
  6.  *
  7.  * Authors: Christophe Mutricy <xtophe -at- videolan -dot- org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_interface.h>
  32. #include <vlc_playlist.h>
  33. #include <vlc_url.h>
  34. #include <gdk-pixbuf/gdk-pixbuf.h>
  35. #include <libnotify/notify.h>
  36. /*****************************************************************************
  37.  * Module descriptor
  38.  ****************************************************************************/
  39. static int  Open    ( vlc_object_t * );
  40. static void Close   ( vlc_object_t * );
  41. #define APPLICATION_NAME "VLC media player"
  42. #define TIMEOUT_TEXT N_("Timeout (ms)")
  43. #define TIMEOUT_LONGTEXT N_("How long the notification will be displayed ")
  44. vlc_module_begin ()
  45.     set_category( CAT_INTERFACE )
  46.     set_subcategory( SUBCAT_INTERFACE_CONTROL )
  47.     set_shortname( N_( "Notify" ) )
  48.     set_description( N_("LibNotify Notification Plugin") )
  49.     add_integer( "notify-timeout", 4000, NULL,
  50.                 TIMEOUT_TEXT, TIMEOUT_LONGTEXT, true )
  51.     set_capability( "interface", 0 )
  52.     set_callbacks( Open, Close )
  53. vlc_module_end ()
  54. /*****************************************************************************
  55.  * Local prototypes
  56.  *****************************************************************************/
  57. static int ItemChange( vlc_object_t *, const char *,
  58.                        vlc_value_t, vlc_value_t, void * );
  59. static int Notify( vlc_object_t *, const char *, GdkPixbuf *, intf_thread_t * );
  60. #define MAX_LENGTH 256
  61. struct intf_sys_t
  62. {
  63.     NotifyNotification *notification;
  64.     vlc_mutex_t     lock;
  65.     bool            b_has_actions;
  66. };
  67. /*****************************************************************************
  68.  * Open: initialize and create stuff
  69.  *****************************************************************************/
  70. static int Open( vlc_object_t *p_this )
  71. {
  72.     intf_thread_t   *p_intf = (intf_thread_t *)p_this;
  73.     intf_sys_t      *p_sys  = malloc( sizeof( *p_sys ) );
  74.     if( !p_sys )
  75.         return VLC_ENOMEM;
  76.     if( !notify_init( APPLICATION_NAME ) )
  77.     {
  78.         free( p_sys );
  79.         msg_Err( p_intf, "can't find notification daemon" );
  80.         return VLC_EGENERIC;
  81.     }
  82.     p_intf->p_sys = p_sys;
  83.     vlc_mutex_init( &p_sys->lock );
  84.     p_sys->notification = NULL;
  85.     p_sys->b_has_actions = false;
  86.     GList *p_caps = notify_get_server_caps ();
  87.     if( p_caps )
  88.     {
  89.         for( GList *c = p_caps; c != NULL; c = c->next )
  90.         {
  91.             if( !strcmp( (char*)c->data, "actions" ) )
  92.             {
  93.                 p_sys->b_has_actions = true;
  94.                 break;
  95.             }
  96.         }
  97.         g_list_foreach( p_caps, (GFunc)g_free, NULL );
  98.         g_list_free( p_caps );
  99.     }
  100.     /* */
  101.     playlist_t *p_playlist = pl_Hold( p_intf );
  102.     var_AddCallback( p_playlist, "item-current", ItemChange, p_intf );
  103.     pl_Release( p_intf );
  104.     return VLC_SUCCESS;
  105. }
  106. /*****************************************************************************
  107.  * Close: destroy interface stuff
  108.  *****************************************************************************/
  109. static void Close( vlc_object_t *p_this )
  110. {
  111.     intf_thread_t   *p_intf = ( intf_thread_t* ) p_this;
  112.     intf_sys_t      *p_sys  = p_intf->p_sys;
  113.     playlist_t *p_playlist = pl_Hold( p_this );
  114.     var_DelCallback( p_playlist, "item-current", ItemChange, p_this );
  115.     pl_Release( p_this );
  116.     if( p_sys->notification )
  117.     {
  118.         GError *p_error = NULL;
  119.         notify_notification_close( p_sys->notification, &p_error );
  120.         g_object_unref( p_sys->notification );
  121.     }
  122.     vlc_mutex_destroy( &p_sys->lock );
  123.     free( p_sys );
  124.     notify_uninit();
  125. }
  126. /*****************************************************************************
  127.  * ItemChange: Playlist item change callback
  128.  *****************************************************************************/
  129. static int ItemChange( vlc_object_t *p_this, const char *psz_var,
  130.                        vlc_value_t oldval, vlc_value_t newval, void *param )
  131. {
  132.     VLC_UNUSED(psz_var); VLC_UNUSED(oldval); VLC_UNUSED(newval);
  133.     char                psz_tmp[MAX_LENGTH];
  134.     char                psz_notify[MAX_LENGTH];
  135.     char                *psz_title      = NULL;
  136.     char                *psz_artist     = NULL;
  137.     char                *psz_album      = NULL;
  138.     char                *psz_arturl     = NULL;
  139.     input_thread_t      *p_input        =  playlist_CurrentInput(
  140.                                                     (playlist_t*) p_this );
  141.     intf_thread_t       *p_intf         = param;
  142.     intf_sys_t          *p_sys          = p_intf->p_sys;
  143.     if( !p_input )
  144.         return VLC_SUCCESS;
  145.     if( p_input->b_dead )
  146.     {
  147.         /* Not playing anything ... */
  148.         vlc_object_release( p_input );
  149.         return VLC_SUCCESS;
  150.     }
  151.     /* Wait a tad so the meta has been fetched
  152.      * FIXME that's awfully wrong */
  153.     msleep( 1000*4 );
  154.     /* Playing something ... */
  155.     input_item_t *p_input_item = input_GetItem( p_input );
  156.     psz_artist = input_item_GetArtist( p_input_item );
  157.     psz_album = input_item_GetAlbum( p_input_item );
  158.     psz_title = input_item_GetTitleFbName( p_input_item );
  159.     if( EMPTY_STR( psz_title ) )
  160.     {  /* Not enough metadata ... */
  161.         free( psz_title );
  162.         free( psz_artist );
  163.         free( psz_album );
  164.         vlc_object_release( p_input );
  165.         return VLC_SUCCESS;
  166.     }
  167.     if( EMPTY_STR( psz_artist ) )
  168.     {
  169.         free( psz_artist );
  170.         psz_artist = NULL;
  171.     }
  172.     if( EMPTY_STR( psz_album ) )
  173.     {
  174.         free( psz_album );
  175.         psz_album = NULL;
  176.     }
  177.     if( psz_artist && psz_album )
  178.         snprintf( psz_tmp, MAX_LENGTH, "<b>%s</b>n%sn[%s]",
  179.                   psz_title, psz_artist, psz_album );
  180.     else if( psz_artist )
  181.         snprintf( psz_tmp, MAX_LENGTH, "<b>%s</b>n%s",
  182.                   psz_title, psz_artist );
  183.     else
  184.         snprintf( psz_tmp, MAX_LENGTH, "<b>%s</b>", psz_title );
  185.     free( psz_title );
  186.     free( psz_artist );
  187.     free( psz_album );
  188.     GdkPixbuf *pix = NULL;
  189.     psz_arturl = input_item_GetArtURL( p_input_item );
  190.     vlc_object_release( p_input );
  191.     if( psz_arturl && !strncmp( psz_arturl, "file://", 7 ) &&
  192.                 decode_URI( psz_arturl + 7 ) )
  193.     { /* scale the art to show it in notify popup */
  194.         GError *p_error = NULL;
  195.         pix = gdk_pixbuf_new_from_file_at_scale( &psz_arturl[7],
  196.                                                  72, 72, TRUE, &p_error );
  197.     }
  198.     else /* else we show state-of-the art logo */
  199.     {
  200.         GError *p_error = NULL;
  201.         char *psz_pixbuf;
  202.         if( asprintf( &psz_pixbuf, "%s/vlc48x48.png", config_GetDataDir() ) >= 0 )
  203.         {
  204.             pix = gdk_pixbuf_new_from_file( psz_pixbuf, &p_error );
  205.             free( psz_pixbuf );
  206.         }
  207.     }
  208.     free( psz_arturl );
  209.     /* we need to replace '&' with '&amp;' because '&' is a keyword of
  210.      * notification-daemon parser */
  211.     const int i_len = strlen( psz_tmp );
  212.     int i_notify = 0;
  213.     for( int i = 0; i < i_len && i_notify < ( MAX_LENGTH - 5 ); i++ )
  214.     { /* we use MAX_LENGTH - 5 because if the last char of psz_tmp is '&'
  215.        * we will need 5 more characters: 'amp;' .
  216.        * however that's unlikely to happen because the last char is '' */
  217.         if( psz_tmp[i] != '&' )
  218.         {
  219.             psz_notify[i_notify] = psz_tmp[i];
  220.         }
  221.         else
  222.         {
  223.             snprintf( &psz_notify[i_notify], 6, "&amp;" );
  224.             i_notify += 4;
  225.         }
  226.         i_notify++;
  227.     }
  228.     psz_notify[i_notify] = '';
  229.     vlc_mutex_lock( &p_sys->lock );
  230.     Notify( p_this, psz_notify, pix, p_intf );
  231.     vlc_mutex_unlock( &p_sys->lock );
  232.     return VLC_SUCCESS;
  233. }
  234. static void Next( NotifyNotification *notification, gchar *psz, gpointer p )
  235. { /* libnotify callback, called when the "Next" button is pressed */
  236.     vlc_object_t *p_object = (vlc_object_t*)p;
  237.     VLC_UNUSED(psz);
  238.     notify_notification_close( notification, NULL );
  239.     playlist_t *p_playlist = pl_Hold( p_object );
  240.     playlist_Next( p_playlist );
  241.     pl_Release( p_object );
  242. }
  243. static void Prev( NotifyNotification *notification, gchar *psz, gpointer p )
  244. { /* libnotify callback, called when the "Previous" button is pressed */
  245.     vlc_object_t *p_object = (vlc_object_t*)p;
  246.     VLC_UNUSED(psz);
  247.     notify_notification_close( notification, NULL );
  248.     playlist_t *p_playlist = pl_Hold( p_object );
  249.     playlist_Prev( p_playlist );
  250.     pl_Release( p_object );
  251. }
  252. static int Notify( vlc_object_t *p_this, const char *psz_temp, GdkPixbuf *pix,
  253.                    intf_thread_t *p_intf )
  254. {
  255.     intf_sys_t *p_sys = p_intf->p_sys;
  256.     NotifyNotification * notification;
  257.     /* Close previous notification if still active */
  258.     if( p_sys->notification )
  259.     {
  260.         GError *p_error = NULL;
  261.         notify_notification_close( p_sys->notification, &p_error );
  262.         g_object_unref( p_sys->notification );
  263.     }
  264.     notification = notify_notification_new( _("Now Playing"),
  265.                                             psz_temp, NULL, NULL );
  266.     notify_notification_set_timeout( notification,
  267.                                      config_GetInt(p_this, "notify-timeout") );
  268.     notify_notification_set_urgency( notification, NOTIFY_URGENCY_LOW );
  269.     if( pix )
  270.     {
  271.         notify_notification_set_icon_from_pixbuf( notification, pix );
  272.         gdk_pixbuf_unref( pix );
  273.     }
  274.     /* Adds previous and next buttons in the notification if actions are supported. */
  275.     if( p_sys->b_has_actions )
  276.     {
  277.       notify_notification_add_action( notification, "previous", _("Previous"), Prev,
  278.                       (gpointer*)p_intf, NULL );
  279.       notify_notification_add_action( notification, "next", _("Next"), Next,
  280.                       (gpointer*)p_intf, NULL );
  281.     }
  282.     notify_notification_show( notification, NULL);
  283.     /* Stores the notification to be able to close it */
  284.     p_sys->notification = notification;
  285.     return VLC_SUCCESS;
  286. }