actions_manager.cpp 11.1 KB
Newer Older
1
/*****************************************************************************
Pere Orga's avatar
Pere Orga committed
2
 * actions_manager.cpp : Controller for the main interface
3
 ****************************************************************************
4
 * Copyright © 2009-2014 VideoLAN and VLC authors
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 * $Id$
 *
 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
 *
 * 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 <vlc_vout.h>
29
#include <vlc_actions.h>
30
#include <vlc_renderer_discovery.h>
31 32

#include "actions_manager.hpp"
33 34 35 36

#include "dialogs_provider.hpp"      /* Opening Dialogs */
#include "input_manager.hpp"         /* THEMIM */
#include "main_interface.hpp"        /* Show playlist */
37
#include "components/controller.hpp" /* Toggle FSC controller width */
38
#include "components/extended_panels.hpp"
39
#include "menus.hpp"
40

41
ActionsManager::ActionsManager( intf_thread_t * _p_i )
42
    : p_intf( _p_i )
43
    , m_scanning( false )
44 45 46 47 48
{
    CONNECT( this, rendererItemAdded( vlc_renderer_item_t* ),
             this, onRendererItemAdded( vlc_renderer_item_t* ) );
    CONNECT( this, rendererItemRemoved( vlc_renderer_item_t* ),
             this, onRendererItemRemoved( vlc_renderer_item_t* ) );
49 50
    m_stop_scan_timer.setSingleShot( true );
    CONNECT( &m_stop_scan_timer, timeout(), this, StopRendererScan() );
51
}
52 53 54

ActionsManager::~ActionsManager()
{
55
    StopRendererScan();
56 57 58 59 60 61 62 63
}

void ActionsManager::doAction( int id_action )
{
    switch( id_action )
    {
        case PLAY_ACTION:
            play(); break;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
64 65 66
        case STOP_ACTION:
            THEMIM->stop(); break;
        case OPEN_ACTION:
67
            THEDP->openDialog(); break;
68
        case PREVIOUS_ACTION:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
69
            THEMIM->prev(); break;
70
        case NEXT_ACTION:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
71
            THEMIM->next(); break;
72
        case SLOWER_ACTION:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
73
            THEMIM->getIM()->slower(); break;
74
        case FASTER_ACTION:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
75
            THEMIM->getIM()->faster(); break;
76 77 78
        case FULLSCREEN_ACTION:
            fullscreen(); break;
        case EXTENDED_ACTION:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
79
            THEDP->extendedDialog(); break;
80 81 82 83 84 85 86 87
        case PLAYLIST_ACTION:
            playlist(); break;
        case SNAPSHOT_ACTION:
            snapshot(); break;
        case RECORD_ACTION:
            record(); break;
        case FRAME_ACTION:
            frame(); break;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
88 89
        case ATOB_ACTION:
            THEMIM->getIM()->setAtoB(); break;
90
        case REVERSE_ACTION:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
91
            THEMIM->getIM()->reverse(); break;
92
        case SKIP_BACK_ACTION:
93
            skipBackward();
94 95
            break;
        case SKIP_FW_ACTION:
96
            skipForward();
97
            break;
98 99
        case QUIT_ACTION:
            THEDP->quit();  break;
100
        case RANDOM_ACTION:
101
            THEMIM->toggleRandom(); break;
102 103
        case INFO_ACTION:
            THEDP->mediaInfoDialog(); break;
104 105
        case OPEN_SUB_ACTION:
            THEDP->loadSubtitlesFile(); break;
106 107 108 109
        case FULLWIDTH_ACTION:
            if( p_intf->p_sys->p_mi )
                p_intf->p_sys->p_mi->getFullscreenControllerWidget()->toggleFullwidth();
            break;
110
        default:
111
            msg_Warn( p_intf, "Action not supported: %i", id_action );
112 113 114 115 116 117
            break;
    }
}

void ActionsManager::play()
{
118
    if( THEPL->current.i_size == 0 && THEPL->items.i_size == 0 )
119 120 121 122 123 124 125 126 127
    {
        /* The playlist is empty, open a file requester */
        THEDP->openFileDialog();
        return;
    }
    THEMIM->togglePlayPause();
}

/**
128
 * TODO
129 130
 * This functions toggle the fullscreen mode
 * If there is no video, it should first activate Visualisations...
131
 * This has also to be fixed in enableVideo()
132 133 134
 */
void ActionsManager::fullscreen()
{
135
    bool fs = var_ToggleBool( THEPL, "fullscreen" );
136
    vout_thread_t *p_vout = THEMIM->getVout();
137 138
    if( p_vout)
    {
139
        var_SetBool( p_vout, "fullscreen", fs );
140 141 142 143 144 145
        vlc_object_release( p_vout );
    }
}

void ActionsManager::snapshot()
{
146
    vout_thread_t *p_vout = THEMIM->getVout();
147 148
    if( p_vout )
    {
149
        var_TriggerCallback( p_vout, "video-snapshot" );
150 151 152 153
        vlc_object_release( p_vout );
    }
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
154
void ActionsManager::playlist()
155
{
156 157
    if( p_intf->p_sys->p_mi )
        p_intf->p_sys->p_mi->togglePlaylist();
158 159 160 161 162 163 164 165
}

void ActionsManager::record()
{
    input_thread_t *p_input = THEMIM->getInput();
    if( p_input )
    {
        /* This method won't work fine if the stream can't be cut anywhere */
166
        var_ToggleBool( p_input, "record" );
167 168 169 170 171 172 173 174 175 176
#if 0
        else
        {
            /* 'record' access-filter is not loaded, we open Save dialog */
            input_item_t *p_item = input_GetItem( p_input );
            if( !p_item )
                return;

            char *psz = input_item_GetURI( p_item );
            if( psz )
177
                THEDP->streamingDialog( NULL, qfu(psz), true );
178 179 180 181 182 183 184 185 186
        }
#endif
    }
}

void ActionsManager::frame()
{
    input_thread_t *p_input = THEMIM->getInput();
    if( p_input )
187
        var_TriggerCallback( p_input, "frame-next" );
188 189
}

190 191
void ActionsManager::toggleMuteAudio()
{
192
    playlist_MuteToggle( THEPL );
193 194 195 196
}

void ActionsManager::AudioUp()
{
197
    playlist_VolumeUp( THEPL, 1, NULL );
198 199 200 201
}

void ActionsManager::AudioDown()
{
202
    playlist_VolumeDown( THEPL, 1, NULL );
203
}
204

205 206
void ActionsManager::skipForward()
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
207 208 209
    input_thread_t *p_input = THEMIM->getInput();
    if( p_input )
        THEMIM->getIM()->jumpFwd();
210 211 212 213
}

void ActionsManager::skipBackward()
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
214 215 216
    input_thread_t *p_input = THEMIM->getInput();
    if( p_input )
        THEMIM->getIM()->jumpBwd();
217 218
}

219
vlc_renderer_item_t* ActionsManager::compareRenderers( const QVariant &obj, vlc_renderer_item_t* p_item )
220
{
221
    if (!obj.canConvert<QVariantHash>())
222
        return NULL;
223 224
    QVariantHash qvh = obj.value<QVariantHash>();
    if (!qvh.contains( "sout" ))
225
        return NULL;
226 227
    vlc_renderer_item_t* p_existing =
            reinterpret_cast<vlc_renderer_item_t*>( qvh["sout"].value<void*>() );
228 229 230 231
    if ( !strcasecmp(vlc_renderer_item_sout( p_existing ),
                    vlc_renderer_item_sout( p_item ) ) )
        return p_existing;
    return NULL;
232 233
}

234
void ActionsManager::onRendererItemAdded(vlc_renderer_item_t* p_item)
235
{
236
    QAction *firstSeparator = NULL;
237

238
    foreach (QAction* action, VLCMenuBar::rendererMenu->actions())
239
    {
240
        if (action->isSeparator())
241
        {
242 243
            firstSeparator = action;
            break;
244
        }
245
        if (compareRenderers( action->data(), p_item ))
246 247
        {
            vlc_renderer_item_release( p_item );
248
            return; /* we already have this item */
249
        }
250
    }
251

252
    QAction *action = new QAction( vlc_renderer_item_flags(p_item) & VLC_RENDERER_CAN_VIDEO ? QIcon( ":/sidebar/movie.svg" ) : QIcon( ":/sidebar/music.svg" ),
253 254
                                   vlc_renderer_item_name(p_item), VLCMenuBar::rendererMenu );
    action->setCheckable(true);
255 256 257 258

    QVariantHash data;
    data.insert( "sout", QVariant::fromValue( reinterpret_cast<void*>( p_item ) ) );
    action->setData( data );
259 260 261 262 263
    if (firstSeparator != NULL)
    {
        VLCMenuBar::rendererMenu->insertAction( firstSeparator, action );
        VLCMenuBar::rendererGroup->addAction(action);
    }
264 265 266 267 268
    else
    {
        vlc_renderer_item_release( p_item );
        delete action;
    }
269 270
}

271
void ActionsManager::onRendererItemRemoved( vlc_renderer_item_t* p_item )
272
{
273 274 275 276
    foreach (QAction* action, VLCMenuBar::rendererMenu->actions())
    {
        if (action->isSeparator())
            continue;
277 278
        vlc_renderer_item_t *p_existing = compareRenderers( action->data(), p_item );
        if (p_existing)
279 280 281
        {
            VLCMenuBar::rendererMenu->removeAction( action );
            VLCMenuBar::rendererGroup->removeAction( action );
282 283
            vlc_renderer_item_release( p_existing );
            break;
284 285
        }
    }
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    // Always release the item as we acquired it before emiting the signal
    vlc_renderer_item_release( p_item );
}

void ActionsManager::renderer_event_item_added( vlc_renderer_discovery_t* p_rd,
                                                vlc_renderer_item_t *p_item )
{
    ActionsManager *self = reinterpret_cast<ActionsManager*>( p_rd->owner.sys );
    vlc_renderer_item_hold( p_item );
    self->emit rendererItemAdded( p_item );
}

void ActionsManager::renderer_event_item_removed( vlc_renderer_discovery_t *p_rd,
                                                  vlc_renderer_item_t *p_item )
{
    ActionsManager *self = reinterpret_cast<ActionsManager*>( p_rd->owner.sys );
    vlc_renderer_item_hold( p_item );
    self->emit rendererItemRemoved( p_item );
304 305
}

306
void ActionsManager::StartRendererScan()
307
{
308 309 310
    m_stop_scan_timer.stop();
    if( m_scanning )
        return;
311

312 313 314 315 316 317 318
    /* SD subnodes */
    char **ppsz_longnames;
    char **ppsz_names;
    if( vlc_rd_get_names( THEPL, &ppsz_names, &ppsz_longnames ) != VLC_SUCCESS )
        return;

    struct vlc_renderer_discovery_owner owner =
319
    {
320 321 322 323
        this,
        renderer_event_item_added,
        renderer_event_item_removed,
    };
324

325 326 327 328 329 330 331 332 333 334 335 336 337 338
    char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
    for( ; *ppsz_name; ppsz_name++, ppsz_longname++ )
    {
        msg_Dbg( p_intf, "starting renderer discovery service %s", *ppsz_longname );
        vlc_renderer_discovery_t* p_rd = vlc_rd_new( VLC_OBJECT(p_intf), *ppsz_name, &owner );
        if( p_rd != NULL )
            m_rds.push_back( p_rd );
        free( *ppsz_name );
        free( *ppsz_longname );
    }
    free( ppsz_names );
    free( ppsz_longnames );
    m_scanning = true;
}
339

340 341 342 343
void ActionsManager::RendererMenuCountdown()
{
    m_stop_scan_timer.start( 20000 );
}
344

345 346 347 348
void ActionsManager::StopRendererScan()
{
    /* reset the list of renderers */
    foreach (QAction* action, VLCMenuBar::rendererMenu->actions())
349
    {
350 351 352 353 354
        QVariant data = action->data();
        if (!data.canConvert<QVariantHash>())
            continue;
        VLCMenuBar::rendererMenu->removeAction(action);
        VLCMenuBar::rendererGroup->removeAction(action);
355
    }
356 357 358 359
    foreach ( vlc_renderer_discovery_t* p_rd, m_rds )
        vlc_rd_release( p_rd );
    m_rds.clear();
    m_scanning = false;
360 361 362 363 364
}

void ActionsManager::RendererSelected( QAction *selected )
{
    QVariant data = selected->data();
365
    vlc_renderer_item_t *p_item = NULL;
366
    if (data.canConvert<QVariantHash>())
367
    {
368
        QVariantHash hash = data.value<QVariantHash>();
369 370 371
        if ( hash.contains( "sout" ) )
            p_item = reinterpret_cast<vlc_renderer_item_t*>(
                        hash["sout"].value<void*>() );
372
    }
373 374 375
    // If we failed to convert the action data to a vlc_renderer_item_t,
    // assume the selected item was invalid, or most likely that "Local" was selected
    playlist_SetRenderer( THEPL, p_item );
376 377
}