[vlc-devel] [PATCHv3 12/12] gui:qt: add a dialog to select the renderer to use

Thomas Guillem thomas at gllm.fr
Tue Mar 29 15:06:43 CEST 2016


From: Steve Lhomme <robux4 at videolabs.io>

limited to the first and only renderer discovery service we have for now
---
 include/vlc_interface.h                       |   1 +
 include/vlc_intf_strings.h                    |   1 +
 modules/gui/qt/Makefile.am                    |   5 +
 modules/gui/qt/actions_manager.cpp            |   3 +
 modules/gui/qt/actions_manager.hpp            |   1 +
 modules/gui/qt/components/controller.cpp      |   4 +
 modules/gui/qt/components/controller.hpp      |  13 +-
 modules/gui/qt/dialogs/renderer.cpp           | 262 ++++++++++++++++++++++++++
 modules/gui/qt/dialogs/renderer.hpp           |  68 +++++++
 modules/gui/qt/dialogs_provider.cpp           |   8 +
 modules/gui/qt/dialogs_provider.hpp           |   3 +
 modules/gui/qt/menus.cpp                      |   5 +
 modules/gui/qt/pixmaps/toolbar/chromecast.png | Bin 0 -> 286 bytes
 modules/gui/qt/ui/renderer.ui                 |  54 ++++++
 modules/gui/qt/vlc.qrc                        |   1 +
 15 files changed, 426 insertions(+), 3 deletions(-)
 create mode 100644 modules/gui/qt/dialogs/renderer.cpp
 create mode 100644 modules/gui/qt/dialogs/renderer.hpp
 create mode 100644 modules/gui/qt/pixmaps/toolbar/chromecast.png
 create mode 100644 modules/gui/qt/ui/renderer.ui

diff --git a/include/vlc_interface.h b/include/vlc_interface.h
index 108384b..6368d54 100644
--- a/include/vlc_interface.h
+++ b/include/vlc_interface.h
@@ -129,6 +129,7 @@ typedef enum vlc_intf_dialog {
     INTF_DIALOG_PREFS,
     INTF_DIALOG_BOOKMARKS,
     INTF_DIALOG_EXTENDED,
+    INTF_DIALOG_RENDERER,
 
     INTF_DIALOG_POPUPMENU = 20,
     INTF_DIALOG_AUDIOPOPUPMENU,
diff --git a/include/vlc_intf_strings.h b/include/vlc_intf_strings.h
index 25c57b3..02f2257 100644
--- a/include/vlc_intf_strings.h
+++ b/include/vlc_intf_strings.h
@@ -58,6 +58,7 @@
 #define I_MENU_GOTOTIME N_("Jump to Specific &Time")
 #define I_MENU_BOOKMARK N_("Custom &Bookmarks")
 #define I_MENU_VLM N_("&VLM Configuration")
+#define I_MENU_RENDERER N_("&Renderer Output")
 
 #define I_MENU_ABOUT N_("&About")
 
diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index b48e4ee..2043938 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -67,6 +67,7 @@ libqt_plugin_la_SOURCES = \
 	dialogs/podcast_configuration.cpp dialogs/podcast_configuration.hpp \
 	dialogs/extensions.cpp dialogs/extensions.hpp \
 	dialogs/fingerprintdialog.cpp dialogs/fingerprintdialog.hpp \
+	dialogs/renderer.cpp dialogs/renderer.hpp \
 	components/extended_panels.cpp components/extended_panels.hpp \
 	components/info_panels.cpp components/info_panels.hpp \
 	components/info_widgets.cpp components/info_widgets.hpp \
@@ -166,6 +167,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	dialogs/firstrun.moc.cpp \
 	dialogs/extensions.moc.cpp \
 	dialogs/fingerprintdialog.moc.cpp \
+	dialogs/renderer.moc.cpp \
 	components/extended_panels.moc.cpp \
 	components/info_panels.moc.cpp \
 	components/info_widgets.moc.cpp \
@@ -223,6 +225,7 @@ nodist_libqt_plugin_la_SOURCES += \
 	ui/about.h \
 	ui/update.h \
 	ui/fingerprintdialog.h \
+	ui/renderer.h \
 	ui/sout.h
 
 # User interface compilation
@@ -260,6 +263,7 @@ libqt_plugin_la_UI = \
 	ui/streampanel.ui \
 	ui/messages_panel.ui \
 	ui/about.ui \
+	ui/renderer.ui \
 	ui/update.ui \
 	ui/sout.ui \
 	ui/vlm.ui \
@@ -362,6 +366,7 @@ DEPS_res = \
 	pixmaps/toolbar/atob.png \
 	pixmaps/toolbar/atob_noa.png \
 	pixmaps/toolbar/atob_nob.png \
+	pixmaps/toolbar/chromecast.png \
 	pixmaps/toolbar/defullscreen.png \
 	pixmaps/toolbar/dvd_menu.png \
 	pixmaps/toolbar/dvd_next.png \
diff --git a/modules/gui/qt/actions_manager.cpp b/modules/gui/qt/actions_manager.cpp
index eff40d9..89f5d22 100644
--- a/modules/gui/qt/actions_manager.cpp
+++ b/modules/gui/qt/actions_manager.cpp
@@ -93,6 +93,9 @@ void ActionsManager::doAction( int id_action )
             if( p_intf->p_sys->p_mi )
                 p_intf->p_sys->p_mi->getFullscreenControllerWidget()->toggleFullwidth();
             break;
+        case RENDERER_ACTION:
+            THEDP->rendererDialog(); break;
+            break;
         default:
             msg_Warn( p_intf, "Action not supported: %i", id_action );
             break;
diff --git a/modules/gui/qt/actions_manager.hpp b/modules/gui/qt/actions_manager.hpp
index 20c10e0..cb3943a 100644
--- a/modules/gui/qt/actions_manager.hpp
+++ b/modules/gui/qt/actions_manager.hpp
@@ -59,6 +59,7 @@ typedef enum actionType_e
     LOOP_ACTION,
     INFO_ACTION,
     OPEN_SUB_ACTION,
+    RENDERER_ACTION,
 } actionType_e;
 
 class ActionsManager : public QObject, public Singleton<ActionsManager>
diff --git a/modules/gui/qt/components/controller.cpp b/modules/gui/qt/components/controller.cpp
index 4630140..677ded4 100644
--- a/modules/gui/qt/components/controller.cpp
+++ b/modules/gui/qt/components/controller.cpp
@@ -474,6 +474,10 @@ QWidget *AbstractController::createWidget( buttonType_e button, int options )
         CONNECT_MAP_SET( play, PLAY_ACTION );
         }
         break;
+    case RENDERER_BUTTON:{
+        NORMAL_BUTTON( RENDERER );
+        }
+        break;
     case ASPECT_RATIO_COMBOBOX:
         widget = new AspectRatioComboBox( p_intf );
         widget->setMinimumHeight( 26 );
diff --git a/modules/gui/qt/components/controller.hpp b/modules/gui/qt/components/controller.hpp
index f3fb18d..a9ba389 100644
--- a/modules/gui/qt/components/controller.hpp
+++ b/modules/gui/qt/components/controller.hpp
@@ -35,7 +35,11 @@
 #include <QSizeGrip>
 
 #define MAIN_TB1_DEFAULT "64;39;64;38;65"
+#if defined(ENABLE_SOUT)
+#define MAIN_TB2_DEFAULT "0-2;64;3;1;4;64;7;9;64;10;20;19;64-4;37;26;65;35-4"
+#else
 #define MAIN_TB2_DEFAULT "0-2;64;3;1;4;64;7;9;64;10;20;19;64-4;37;65;35-4"
+#endif
 #define ADV_TB_DEFAULT "12;11;13;14"
 #define INPT_TB_DEFAULT "43;33-4;44"
 #define FSC_TB_DEFAULT "0-2;64;3;1;4;64;37;64;38;64;8;65;25;35-4;34"
@@ -81,6 +85,7 @@ typedef enum buttonType_e
     NEXT_BUTTON,
     OPEN_SUB_BUTTON,
     FULLWIDTH_BUTTON,
+    RENDERER_BUTTON,
     BUTTON_MAX,
 
     SPLITTER = 0x20,
@@ -110,7 +115,7 @@ static const char* const nameL[BUTTON_MAX] = { N_("Play"), N_("Stop"), N_("Open"
     N_("Record"), N_("A→B Loop"), N_("Frame By Frame"), N_("Trickplay Reverse"),
     N_("Step backward" ), N_("Step forward"), N_("Quit"), N_("Random"),
     N_("Loop / Repeat"), N_("Information"), N_("Previous"), N_("Next"),
-    N_("Open subtitles"), N_("Dock fullscreen controller")
+    N_("Open subtitles"), N_("Dock fullscreen controller"), N_("Renderer output")
 };
 static const char* const tooltipL[BUTTON_MAX] = { I_PLAY_TOOLTIP,
     N_("Stop playback"), N_("Open a medium"),
@@ -124,7 +129,8 @@ static const char* const tooltipL[BUTTON_MAX] = { I_PLAY_TOOLTIP,
     N_("Random"), N_("Change the loop and repeat modes"), N_("Information"),
     N_("Previous media in the playlist"), N_("Next media in the playlist"),
     N_("Open subtitle file"),
-    N_("Dock/undock fullscreen controller to/from bottom of screen")
+    N_("Dock/undock fullscreen controller to/from bottom of screen"),
+    N_("Select a Renderer device to output video/audio")
 };
 static const QString iconL[BUTTON_MAX] ={ ":/toolbar/play_b", ":/toolbar/stop_b",
     ":/toolbar/eject", ":/toolbar/previous_b", ":/toolbar/next_b",
@@ -134,7 +140,8 @@ static const QString iconL[BUTTON_MAX] ={ ":/toolbar/play_b", ":/toolbar/stop_b"
     ":/toolbar/frame", ":/toolbar/reverse", ":/toolbar/skip_back",
     ":/toolbar/skip_fw", ":/toolbar/clear", ":/buttons/playlist/shuffle_on",
     ":/buttons/playlist/repeat_all", ":/menu/info",
-    ":/toolbar/previous_b", ":/toolbar/next_b", ":/toolbar/eject", ":/toolbar/space"
+    ":/toolbar/previous_b", ":/toolbar/next_b", ":/toolbar/eject", ":/toolbar/space",
+    ":/toolbar/chromecast"
 };
 
 enum
diff --git a/modules/gui/qt/dialogs/renderer.cpp b/modules/gui/qt/dialogs/renderer.cpp
new file mode 100644
index 0000000..6910a3e
--- /dev/null
+++ b/modules/gui/qt/dialogs/renderer.cpp
@@ -0,0 +1,262 @@
+/*****************************************************************************
+ * renderer.cpp : Renderer output dialog
+ ****************************************************************************
+ * Copyright (C) 2015-2016 the VideoLAN team
+ *
+ * $Id$
+ *
+ * Authors: Steve Lhomme <robux4 at videolabs.io>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <sstream>
+
+#include <vlc_common.h>
+#include <vlc_access.h>
+#include <vlc_renderer.h>
+#include <vlc_services_discovery.h>
+#include <vlc_url.h>
+
+#include "dialogs/renderer.hpp"
+
+class RendererItem : public QListWidgetItem
+{
+public:
+    RendererItem(vlc_renderer_item *obj)
+        : QListWidgetItem( vlc_renderer_item_flags(obj) & VLC_RENDERER_CAN_VIDEO ? QIcon( ":/sidebar/movie" ) : QIcon( ":/sidebar/music" ),
+                           qfu( vlc_renderer_item_name(obj) ).append(" (").append(RendererItemIP(obj)).append(')'))
+    {
+        m_obj = vlc_renderer_item_hold(obj);
+    }
+    ~RendererItem()
+    {
+        vlc_renderer_item_release(m_obj);
+    }
+
+protected:
+    vlc_renderer_item* m_obj;
+
+    friend class RendererDialog;
+
+private:
+    static QString RendererItemIP( const vlc_renderer_item *obj )
+    {
+        vlc_url_t url;
+        vlc_UrlParse(&url, vlc_renderer_item_uri(obj));
+        QString result = QString(url.psz_host);
+        vlc_UrlClean(&url);
+        return result;
+    }
+};
+
+extern "C" void discovery_event_received( const vlc_event_t * p_event, void * user_data )
+{
+    RendererDialog *p_this = reinterpret_cast<RendererDialog*>(user_data);
+    p_this->discoveryEventReceived( p_event );
+}
+
+RendererDialog::RendererDialog( intf_thread_t *_p_intf )
+               : QVLCDialog( (QWidget*)_p_intf->p_sys->p_mi, _p_intf )
+               , p_sd( NULL )
+               , b_sd_started( false )
+{
+    setWindowTitle( qtr( "Renderer Output" ) );
+    setWindowRole( "vlc-renderer" );
+
+    /* Build Ui */
+    ui.setupUi( this );
+
+    CONNECT( ui.buttonBox, accepted(), this, accept() );
+    CONNECT( ui.buttonBox, rejected(), this, onReject() );
+    CONNECT( ui.receiversListWidget, itemDoubleClicked(QListWidgetItem*), this, accept());
+
+    QVLCTools::restoreWidgetPosition( p_intf, "Renderer", this, QSize( 400 , 440 ) );
+}
+
+RendererDialog::~RendererDialog()
+{
+    if ( p_sd != NULL )
+        vlc_sd_Destroy( p_sd );
+}
+
+void RendererDialog::onReject()
+{
+    setRenderer( NULL );
+
+    QVLCDialog::reject();
+}
+
+void RendererDialog::close()
+{
+    QVLCTools::saveWidgetPosition( p_intf, "Renderer", this );
+
+    QVLCDialog::close();
+}
+
+void RendererDialog::setVisible(bool visible)
+{
+    QVLCDialog::setVisible(visible);
+
+    if (visible)
+    {
+        /* SD subnodes */
+        char **ppsz_longnames;
+        int *p_categories;
+        char **ppsz_names = vlc_sd_GetNames( THEPL, &ppsz_longnames, &p_categories );
+        if( !ppsz_names )
+            return;
+
+        char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
+        int *p_category = p_categories;
+        for( ; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++ )
+        {
+            if( *p_category == SD_CAT_RENDERER )
+            {
+                /* TODO launch all discovery services for renderers */
+                msg_Dbg( p_intf, "starting renderer discovery service %s", *ppsz_longname );
+                if ( p_sd == NULL )
+                {
+                    p_sd = vlc_sd_Create( VLC_OBJECT(p_intf), *ppsz_name );
+                    if( !p_sd )
+                        msg_Err( p_intf, "Could not start renderer discovery services" );
+                }
+                break;
+            }
+        }
+        free( ppsz_names );
+        free( ppsz_longnames );
+        free( p_categories );
+
+        if ( p_sd != NULL )
+        {
+            int row = -1;
+            input_thread_t *p_input = playlist_CurrentInput( THEPL );
+            if ( p_input != NULL )
+            {
+                vlc_renderer *p_current_renderer = input_HoldRenderer( p_input );
+                if ( p_current_renderer != NULL )
+                {
+                    for ( row = 0 ; row < ui.receiversListWidget->count(); row++ )
+                    {
+                        RendererItem *rowItem = reinterpret_cast<RendererItem*>( ui.receiversListWidget->item( row ) );
+                        if ( vlc_renderer_equals( p_current_renderer, vlc_renderer_item_uri( rowItem->m_obj ) ) )
+                            break;
+                    }
+                    vlc_object_release( p_current_renderer );
+                    if ( row == ui.receiversListWidget->count() )
+                        row = -1;
+                }
+                vlc_object_release( p_input );
+            }
+            ui.receiversListWidget->setCurrentRow( row );
+
+            if ( !b_sd_started )
+            {
+                vlc_event_manager_t *em = services_discovery_EventManager( p_sd );
+                vlc_event_attach( em, vlc_ServicesDiscoveryRendererAdded, discovery_event_received, this );
+                vlc_event_attach( em, vlc_ServicesDiscoveryRendererRemoved, discovery_event_received, this );
+
+                b_sd_started = vlc_sd_Start( p_sd );
+                if ( !b_sd_started )
+                {
+                    vlc_event_detach( em, vlc_ServicesDiscoveryRendererAdded, discovery_event_received, this);
+                    vlc_event_detach( em, vlc_ServicesDiscoveryRendererRemoved, discovery_event_received, this);
+                }
+            }
+        }
+    }
+    else
+    {
+        if ( p_sd != NULL )
+        {
+            if ( b_sd_started )
+            {
+                vlc_event_manager_t *em = services_discovery_EventManager( p_sd );
+                vlc_event_detach( em, vlc_ServicesDiscoveryRendererAdded, discovery_event_received, this);
+                vlc_event_detach( em, vlc_ServicesDiscoveryRendererRemoved, discovery_event_received, this);
+
+                vlc_sd_Stop( p_sd );
+                b_sd_started = false;
+            }
+        }
+    }
+}
+
+void RendererDialog::accept()
+{
+    /* get the selected one in the listview if any */
+    QListWidgetItem *current = ui.receiversListWidget->currentItem();
+    if (current != NULL)
+    {
+        RendererItem *rowItem = reinterpret_cast<RendererItem*>(current);
+        msg_Dbg( p_intf, "selecting Renderer %s %s", vlc_renderer_item_name(rowItem->m_obj),
+                 vlc_renderer_item_uri(rowItem->m_obj) );
+
+        setRenderer( vlc_renderer_item_uri( rowItem->m_obj ) );
+    }
+
+    QVLCDialog::accept();
+}
+
+void RendererDialog::discoveryEventReceived( const vlc_event_t * p_event )
+{
+    if ( p_event->type == vlc_ServicesDiscoveryRendererAdded )
+    {
+        vlc_renderer_item *p_item =  p_event->u.services_discovery_renderer_added.p_new_item;
+
+        int row = 0;
+        for ( ; row < ui.receiversListWidget->count(); row++ )
+        {
+            RendererItem *rowItem = reinterpret_cast<RendererItem*>( ui.receiversListWidget->item( row ) );
+            if ( !strcmp( vlc_renderer_item_uri( p_item ), vlc_renderer_item_uri( rowItem->m_obj ) ) )
+                return;
+        }
+
+        RendererItem *newItem = new RendererItem(p_item);
+        ui.receiversListWidget->addItem( newItem );
+
+        input_thread_t *p_input = playlist_CurrentInput( THEPL );
+        if ( p_input != NULL )
+        {
+            vlc_renderer *p_current_renderer = input_HoldRenderer( p_input );
+            if ( p_current_renderer != NULL )
+            {
+                if ( vlc_renderer_equals( p_current_renderer, vlc_renderer_item_uri( p_item) ) )
+                    ui.receiversListWidget->setCurrentItem( newItem );
+                vlc_object_release( p_current_renderer );
+            }
+            vlc_object_release( p_input );
+        }
+    }
+}
+
+void RendererDialog::setRenderer( const char *psz_renderer )
+{
+    const char *psz_old_renderer = var_GetString( THEPL, "renderer" );
+    if ( psz_renderer == NULL )
+        psz_renderer = "";
+    if ( !strcmp( psz_old_renderer, psz_renderer ) )
+        return;
+
+    var_SetString( THEPL, "renderer", psz_renderer );
+    /* TODO: restart the playback */
+}
diff --git a/modules/gui/qt/dialogs/renderer.hpp b/modules/gui/qt/dialogs/renderer.hpp
new file mode 100644
index 0000000..bc43e31
--- /dev/null
+++ b/modules/gui/qt/dialogs/renderer.hpp
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * renderer.hpp : Renderer output dialog
+ ****************************************************************************
+ * Copyright ( C ) 2015 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Steve Lhomme <robux4 at videolabs.io>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef QVLC_RENDERER_DIALOG_H_
+#define QVLC_RENDERER_DIALOG_H_ 1
+
+#include "util/qvlcframe.hpp"
+#include "util/singleton.hpp"
+#include "ui/renderer.h"
+
+#include <QMutex>
+#include <QAtomicInt>
+
+class QPushButton;
+class QTreeWidget;
+class QTreeWidgetItem;
+class MsgEvent;
+
+class RendererDialog : public QVLCDialog, public Singleton<RendererDialog>
+{
+    Q_OBJECT
+
+public:
+    void discoveryEventReceived( const vlc_event_t * p_event );
+    void setVisible(bool visible);
+
+private:
+    RendererDialog( intf_thread_t * );
+    virtual ~RendererDialog();
+
+    Ui::rendererWidget ui;
+    void sinkMessage( const MsgEvent * );
+
+private slots:
+    void accept();
+    void onReject();
+    void close();
+
+private:
+
+    friend class          Singleton<RendererDialog>;
+    services_discovery_t *p_sd;
+    bool                  b_sd_started;
+    void                  setRenderer( const char *psz_renderer );
+};
+
+
+#endif
diff --git a/modules/gui/qt/dialogs_provider.cpp b/modules/gui/qt/dialogs_provider.cpp
index 0eade63..00a8382 100644
--- a/modules/gui/qt/dialogs_provider.cpp
+++ b/modules/gui/qt/dialogs_provider.cpp
@@ -57,6 +57,7 @@
 #include "dialogs/external.hpp"
 #include "dialogs/epg.hpp"
 #include "dialogs/errors.hpp"
+#include "dialogs/renderer.hpp"
 
 #include <QEvent>
 #include <QApplication>
@@ -153,6 +154,8 @@ void DialogsProvider::customEvent( QEvent *event )
            bookmarksDialog(); break;
         case INTF_DIALOG_EXTENDED:
            extendedDialog(); break;
+        case INTF_DIALOG_RENDERER:
+           rendererDialog(); break;
         case INTF_DIALOG_SENDKEY:
            sendKey( de->i_arg ); break;
 #ifdef ENABLE_VLM
@@ -234,6 +237,11 @@ void DialogsProvider::extendedDialog()
         extDialog->hide();
 }
 
+void DialogsProvider::rendererDialog()
+{
+    RendererDialog::getInstance( p_intf )->toggleVisible();
+}
+
 void DialogsProvider::synchroDialog()
 {
     ExtendedDialog *extDialog = ExtendedDialog::getInstance(p_intf );
diff --git a/modules/gui/qt/dialogs_provider.hpp b/modules/gui/qt/dialogs_provider.hpp
index 01faa11..8de4fb5 100644
--- a/modules/gui/qt/dialogs_provider.hpp
+++ b/modules/gui/qt/dialogs_provider.hpp
@@ -124,6 +124,9 @@ public slots:
     void mediaCodecDialog();
     void prefsDialog();
     void extendedDialog();
+#if defined(ENABLE_SOUT)
+    void rendererDialog();
+#endif
     void synchroDialog();
     void messagesDialog();
     void sendKey( int key );
diff --git a/modules/gui/qt/menus.cpp b/modules/gui/qt/menus.cpp
index 3f42917..67017a2 100644
--- a/modules/gui/qt/menus.cpp
+++ b/modules/gui/qt/menus.cpp
@@ -428,6 +428,11 @@ QMenu *VLCMenuBar::ToolsMenu( intf_thread_t *p_intf, QMenu *menu )
         "Ctrl+Shift+W" );
 #endif
 
+#if defined(ENABLE_SOUT)
+    addDPStaticEntry( menu, qtr( I_MENU_RENDERER ), "", SLOT( rendererDialog() ),
+        "Ctrl+Shift+R" );
+#endif
+
     addDPStaticEntry( menu, qtr( "Program Guide" ), "", SLOT( epgDialog() ),
         "" );
 
diff --git a/modules/gui/qt/pixmaps/toolbar/chromecast.png b/modules/gui/qt/pixmaps/toolbar/chromecast.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac2929586cdfbcaa82af6b1709579b8c75dc1830
GIT binary patch
literal 286
zcmeAS at N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
z3=G`DAk4 at xYmNj^kiEpy*OmP~4>OmEN&bf;ia?>&o-U3d7N^f%QtW186gc|v{wcQE
z2^*qBW<PB at n6yn+;xCW*lLJ{B^*h`S>L+aZ&A4TrZ@}c2izIALbIrbT*Z4=m14D!V
zGaHXvuV~ocQ_3g2K+jB5%v?Z~(LQ21gNWky`~TzFGLoi?e(2`3;@He!XK-A=d&(uI
zWflwN;x{<_i*)Fa+;{Pqdf1D^o>OygzB=ook=)O?ub`uPy1OS&l5tn_6?g9FD+MkO
b)|Rr?w(DPiQ8J|#=xhd0S3j3^P6<r_#RX|s

literal 0
HcmV?d00001

diff --git a/modules/gui/qt/ui/renderer.ui b/modules/gui/qt/ui/renderer.ui
new file mode 100644
index 0000000..67e7eda
--- /dev/null
+++ b/modules/gui/qt/ui/renderer.ui
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>rendererWidget</class>
+ <widget class="QWidget" name="rendererWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>570</width>
+    <height>440</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Renderer Output</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Available Renderers</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QListWidget" name="receiversListWidget">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc
index 20954cd..25dd853 100644
--- a/modules/gui/qt/vlc.qrc
+++ b/modules/gui/qt/vlc.qrc
@@ -42,6 +42,7 @@
         <file alias="previous_b">pixmaps/previous.png</file>
         <file alias="eject">pixmaps/eject.png</file>
         <file alias="fullscreen">pixmaps/toolbar/fullscreen.png</file>
+        <file alias="chromecast">pixmaps/toolbar/chromecast.png</file>
         <file alias="defullscreen">pixmaps/toolbar/defullscreen.png</file>
         <file alias="extended">pixmaps/toolbar/extended_16px.png</file>
         <file alias="playlist">pixmaps/playlist/playlist.png</file>
-- 
2.8.0.rc3



More information about the vlc-devel mailing list