diff --git a/modules/gui/qt/actions_manager.cpp b/modules/gui/qt/actions_manager.cpp index 89f5d22497..8296032619 100644 --- a/modules/gui/qt/actions_manager.cpp +++ b/modules/gui/qt/actions_manager.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "actions_manager.hpp" @@ -35,10 +36,29 @@ #include "main_interface.hpp" /* Show playlist */ #include "components/controller.hpp" /* Toggle FSC controller width */ #include "components/extended_panels.hpp" +#include "menus.hpp" ActionsManager::ActionsManager( intf_thread_t * _p_i ) { p_intf = _p_i; + p_rd = NULL; + b_rd_started = false; +} + +ActionsManager::~ActionsManager() +{ + if ( p_rd != NULL ) + { + if (b_rd_started) + { + vlc_event_manager_t *em = vlc_rd_event_manager( p_rd ); + vlc_event_detach( em, vlc_RendererDiscoveryItemAdded, renderer_event_received, p_intf); + vlc_event_detach( em, vlc_RendererDiscoveryItemRemoved, renderer_event_received, p_intf); + + vlc_rd_stop( p_rd ); + } + vlc_rd_release( p_rd ); + } } void ActionsManager::doAction( int id_action ) @@ -213,3 +233,155 @@ void ActionsManager::PPaction( QAction *a ) ExtVideo::setPostprocessing( p_intf, i_q ); } + +bool ActionsManager::isItemSout( QVariant & m_obj, const char *psz_sout, bool as_output ) +{ + if ( psz_sout == NULL ) + return false; + if (!m_obj.canConvert()) + return false; + + QString renderer(psz_sout); + if ( as_output && renderer.at(0) == '#' ) + renderer = renderer.right( renderer.length() - 1 ); + return QString::compare( m_obj.toString(), renderer, Qt::CaseInsensitive) == 0; +} + +void ActionsManager::renderer_event_received( const vlc_event_t * p_event, void * user_data ) +{ + intf_thread_t *p_intf = reinterpret_cast(user_data); + + if ( p_event->type == vlc_RendererDiscoveryItemAdded ) + { + vlc_renderer_item *p_item = p_event->u.renderer_discovery_item_added.p_new_item; + + QAction *firstSeparator = NULL; + foreach (QAction* action, VLCMenuBar::rendererMenu->actions()) + { + if (action->isSeparator()) + { + firstSeparator = action; + break; + } + QVariant v = action->data(); + if ( isItemSout( v, vlc_renderer_item_sout( p_item ), false ) ) + return; /* we already have this item */ + } + + QVariant data(vlc_renderer_item_sout( p_item )); + + QAction *action = new QAction( vlc_renderer_item_flags(p_item) & VLC_RENDERER_CAN_VIDEO ? QIcon( ":/sidebar/movie" ) : QIcon( ":/sidebar/music" ), + vlc_renderer_item_name(p_item), VLCMenuBar::rendererMenu ); + action->setCheckable(true); + action->setData(data); + if (firstSeparator != NULL) + { + VLCMenuBar::rendererMenu->insertAction( firstSeparator, action ); + VLCMenuBar::rendererGroup->addAction(action); + } + + char *psz_renderer = var_InheritString( THEPL, "sout" ); + if ( psz_renderer != NULL ) + { + if ( isItemSout( data, psz_renderer, true ) ) + action->setChecked( true ); + free( psz_renderer ); + } + + CONNECT( VLCMenuBar::rendererGroup, triggered(QAction*), ActionsManager::getInstance( p_intf ), RendererSelected( QAction* ) ); + } +} + +void ActionsManager::ScanRendererAction(bool checked) +{ + if (checked == b_rd_started) + return; /* nothing changed */ + + if (checked) + { + /* reset the list of renderers */ + foreach (QAction* action, VLCMenuBar::rendererMenu->actions()) + { + QVariant data = action->data(); + if (!data.canConvert()) + continue; + VLCMenuBar::rendererMenu->removeAction(action); + VLCMenuBar::rendererGroup->removeAction(action); + } + char *psz_renderer = var_InheritString( THEPL, "sout" ); + if ( psz_renderer == NULL || *psz_renderer == '\0' ) + { + foreach (QAction* action, VLCMenuBar::rendererMenu->actions()) + { + if (!action->data().canConvert()) + continue; + if (!action->isSeparator()) + action->setChecked(true); + break; + } + } + free( psz_renderer ); + + /* SD subnodes */ + char **ppsz_longnames; + char **ppsz_names; + if( vlc_rd_get_names( THEPL, &ppsz_names, &ppsz_longnames ) != VLC_SUCCESS ) + return; + + char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames; + for( ; *ppsz_name; ppsz_name++, ppsz_longname++ ) + { + /* TODO launch all discovery services for renderers */ + msg_Dbg( p_intf, "starting renderer discovery service %s", *ppsz_longname ); + if ( p_rd == NULL ) + { + p_rd = vlc_rd_new( VLC_OBJECT(p_intf), *ppsz_name ); + if( !p_rd ) + msg_Err( p_intf, "Could not start renderer discovery services" ); + } + break; + } + free( ppsz_names ); + free( ppsz_longnames ); + + if ( p_rd != NULL ) + { + vlc_event_manager_t *em = vlc_rd_event_manager( p_rd ); + vlc_event_attach( em, vlc_RendererDiscoveryItemAdded, renderer_event_received, p_intf); + vlc_event_attach( em, vlc_RendererDiscoveryItemRemoved, renderer_event_received, p_intf); + + b_rd_started = vlc_rd_start( p_rd ) == VLC_SUCCESS; + if ( !b_rd_started ) + { + vlc_event_detach( em, vlc_RendererDiscoveryItemAdded, renderer_event_received, p_intf); + vlc_event_detach( em, vlc_RendererDiscoveryItemRemoved, renderer_event_received, p_intf); + } + } + } + else + { + if ( p_rd != NULL ) + { + vlc_event_manager_t *em = vlc_rd_event_manager( p_rd ); + vlc_event_detach( em, vlc_RendererDiscoveryItemAdded, renderer_event_received, p_intf); + vlc_event_detach( em, vlc_RendererDiscoveryItemRemoved, renderer_event_received, p_intf); + + vlc_rd_stop( p_rd ); + } + b_rd_started = false; + } +} + +void ActionsManager::RendererSelected( QAction *selected ) +{ + QString s_sout; + QVariant data = selected->data(); + if (data.canConvert()) + { + s_sout.append('#'); + s_sout.append(data.toString()); + } + msg_Dbg( p_intf, "using sout: '%s'", s_sout.toUtf8().constData() ); + var_SetString( THEPL, "sout", s_sout.toUtf8().constData() ); +} + diff --git a/modules/gui/qt/actions_manager.hpp b/modules/gui/qt/actions_manager.hpp index cb3943a434..5b5b3e6bff 100644 --- a/modules/gui/qt/actions_manager.hpp +++ b/modules/gui/qt/actions_manager.hpp @@ -72,9 +72,14 @@ public: private: ActionsManager( intf_thread_t *_p_i ); - virtual ~ActionsManager() {} + virtual ~ActionsManager(); intf_thread_t *p_intf; + vlc_renderer_discovery *p_rd; + + bool b_rd_started; + static void renderer_event_received( const vlc_event_t * p_event, void * user_data ); + static bool isItemSout( QVariant & m_obj, const char *psz_sout, bool as_output ); public slots: void toggleMuteAudio(); @@ -85,6 +90,8 @@ public slots: void skipForward(); void skipBackward(); void PPaction( QAction * ); + void ScanRendererAction( bool ); + void RendererSelected( QAction * ); protected slots: void fullscreen(); diff --git a/modules/gui/qt/menus.cpp b/modules/gui/qt/menus.cpp index 2f70f57a16..c770995afd 100644 --- a/modules/gui/qt/menus.cpp +++ b/modules/gui/qt/menus.cpp @@ -82,6 +82,8 @@ static QActionGroup *currentGroup; QMenu *VLCMenuBar::recentsMenu = NULL; QMenu *VLCMenuBar::audioDeviceMenu = NULL; QMenu *VLCMenuBar::ppMenu = NULL; +QMenu *VLCMenuBar::rendererMenu = NULL; +QActionGroup *VLCMenuBar::rendererGroup = NULL; /** * @brief Add static entries to DP in menus @@ -672,6 +674,10 @@ QMenu *VLCMenuBar::VideoMenu( intf_thread_t *p_intf, QMenu *current ) { addActionWithSubmenu( current, "video-es", qtr( "Video &Track" ) ); + current->addSeparator(); + rendererMenu = RendererMenu( p_intf ); + current->addMenu( rendererMenu ); + current->addSeparator(); /* Surface modifiers */ addActionWithCheckbox( current, "fullscreen", qtr( "&Fullscreen" ) ); @@ -1621,6 +1627,34 @@ void VLCMenuBar::updateRecents( intf_thread_t *p_intf ) } } +QMenu *VLCMenuBar::RendererMenu( intf_thread_t *p_intf ) +{ + QMenu *submenu = new QMenu( qtr("&Renderer") ); + + rendererGroup = new QActionGroup(submenu); + + QAction *action = new QAction( qtr(""), submenu ); + action->setCheckable(true); + submenu->addAction( action ); + rendererGroup->addAction(action); + + char *psz_renderer = var_InheritString( THEPL, "sout" ); + if ( psz_renderer == NULL ) + action->setChecked( true ); + else + free( psz_renderer ); + + submenu->addSeparator(); + + action = new QAction( qtr("Scan"), submenu ); + action->setCheckable(true); + submenu->addAction( action ); + + CONNECT( action, triggered(bool), ActionsManager::getInstance( p_intf ), ScanRendererAction( bool ) ); + + return submenu; +} + QMenu *VLCMenuBar::PPMenu( intf_thread_t *p_intf ) { int i_q = ExtVideo::getPostprocessing( p_intf ); diff --git a/modules/gui/qt/menus.hpp b/modules/gui/qt/menus.hpp index 3d69a6aafb..222c2ca39f 100644 --- a/modules/gui/qt/menus.hpp +++ b/modules/gui/qt/menus.hpp @@ -95,6 +95,8 @@ public: Q_DECLARE_FLAGS(actionflags, actionflag) static QMenu *ppMenu; + static QMenu *rendererMenu; + static QActionGroup *rendererGroup; private: /* All main Menus */ @@ -131,6 +133,7 @@ private: static QMenu *HelpMenu( QWidget * ); static QMenu *PPMenu( intf_thread_t *p_intf ); + static QMenu *RendererMenu( intf_thread_t *p_intf ); /* Popups Menus */ static void PopupMenuStaticEntries( QMenu *menu );