vlcplugin_base.cpp 22.2 KB
Newer Older
1
/*****************************************************************************
2
 * vlcplugin_base.cpp: a VLC plugin for Mozilla
3
 *****************************************************************************
4
 * Copyright (C) 2002-2012 VLC authors and VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Damien Fouilleul <damienf.fouilleul@laposte.net>
8
 *          Jean-Paul Saman <jpsaman@videolan.org>
9
 *          Sergey Radionov <rsatom@gmail.com>
10
 *          Cheng Sun <chengsun9@gmail.com>
11 12 13
 *          Yannick Brehon <y.brehon@qiplay.com>
 *          Felix Paul Kühne <fkuehne # videolan.org>
 *          Ludovic Fauvet <etix@videolan.org>
14
 *          Hugo Beauzée-Luyssen <hugo@beauzee.fr>
15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
28
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29 30 31 32 33
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
34

35 36 37 38
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Ludovic Fauvet's avatar
Ludovic Fauvet committed
39
#include "vlcplugin_base.h"
40
#include "vlcplugin.h"
Jean-Paul Saman's avatar
Jean-Paul Saman committed
41

42
#include "npruntime/npolibvlc.h"
43

44
#include <cctype>
45

46 47 48
#include <cstdio>
#include <cstdlib>
#include <cstring>
49

Jean-Paul Saman's avatar
Jean-Paul Saman committed
50
/*****************************************************************************
51
 * VlcPluginBase constructor and destructor
Jean-Paul Saman's avatar
Jean-Paul Saman committed
52
 *****************************************************************************/
53
VlcPluginBase::VlcPluginBase( NPP instance, NPuint16_t mode ) :
Jean-Paul Saman's avatar
Jean-Paul Saman committed
54 55 56 57 58 59
    i_npmode(mode),
    b_stream(0),
    psz_target(NULL),
    p_scriptClass(NULL),
    p_browser(instance),
    psz_baseURL(NULL)
60
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
61
    memset(&npwindow, 0, sizeof(NPWindow));
62 63
}

Jean-Paul Saman's avatar
Jean-Paul Saman committed
64
static bool boolValue(const char *value) {
Ludovic Fauvet's avatar
Ludovic Fauvet committed
65
    return ( *value == '\0' ||
66
             !strcmp(value, "1") ||
Jean-Paul Saman's avatar
Jean-Paul Saman committed
67 68 69
             !strcasecmp(value, "true") ||
             !strcasecmp(value, "yes") );
}
70

71
NPError VlcPluginBase::init(int argc, char* const argn[], char* const argv[])
72
{
73
    /* prepare VLC command line */
74
    const char *ppsz_argv[MAX_PARAMS];
75
    int ppsz_argc = 0;
76

77 78 79 80
#ifndef NDEBUG
    ppsz_argv[ppsz_argc++] = "--no-plugins-cache";
#endif

81
    /* locate VLC module path */
Felix Paul Kühne's avatar
Felix Paul Kühne committed
82
#ifdef XP_WIN
83 84 85 86 87
    HKEY h_key;
    DWORD i_type, i_data = MAX_PATH + 1;
    char p_data[MAX_PATH + 1];
    if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
                      0, KEY_READ, &h_key ) == ERROR_SUCCESS )
88
    {
89 90 91 92 93
         if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
                              (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
         {
             if( i_type == REG_SZ )
             {
94
                 strcat( p_data, "\\plugins" );
95 96
                 ppsz_argv[ppsz_argc++] = "--plugin-path";
                 ppsz_argv[ppsz_argc++] = p_data;
97 98 99
             }
         }
         RegCloseKey( h_key );
100
    }
101
    ppsz_argv[ppsz_argc++] = "--no-one-instance";
102

103 104
#endif
#ifdef XP_MACOSX
105
    ppsz_argv[ppsz_argc++] = "--vout=caopengllayer";
106 107 108
    ppsz_argv[ppsz_argc++] = "--scaletempo-stride=30";
    ppsz_argv[ppsz_argc++] = "--scaletempo-overlap=0,2";
    ppsz_argv[ppsz_argc++] = "--scaletempo-search=14";
109
    ppsz_argv[ppsz_argc++] = "--auhal-volume=256";
110 111
    ppsz_argv[ppsz_argc++] = "--auhal-audio-device=0";
    ppsz_argv[ppsz_argc++] = "--no-volume-save";
Felix Paul Kühne's avatar
Felix Paul Kühne committed
112
#endif
113

114
    /* common settings */
115
#ifndef NDEBUG
116
    ppsz_argv[ppsz_argc++] = "-vv";
117 118 119
#else
    ppsz_argv[ppsz_argc++] = "--quiet";
#endif
120 121
    ppsz_argv[ppsz_argc++] = "--no-stats";
    ppsz_argv[ppsz_argc++] = "--no-media-library";
122
    ppsz_argv[ppsz_argc++] = "--intf=dummy";
123
    ppsz_argv[ppsz_argc++] = "--no-video-title-show";
Christophe Mutricy's avatar
Christophe Mutricy committed
124
    ppsz_argv[ppsz_argc++] = "--no-xlib";
125

126
    bool b_autoloop = false;
127
    bool b_mute = false;
128
    int i_volume = -1;
129

130
    /* parse plugin arguments */
131
    for( int i = 0; (i < argc) && (ppsz_argc < MAX_PARAMS); i++ )
132
    {
133
       /* fprintf(stderr, "argn=%s, argv=%s\n", argn[i], argv[i]); */
134 135 136 137 138 139 140 141

        if( !strcmp( argn[i], "target" )
         || !strcmp( argn[i], "mrl")
         || !strcmp( argn[i], "filename")
         || !strcmp( argn[i], "src") )
        {
            psz_target = argv[i];
        }
142 143
        else if( !strcmp( argn[i], "text" ) )
        {
144
            set_bg_text( argv[i] );
145
        }
146 147 148
        else if( !strcmp( argn[i], "autoplay")
              || !strcmp( argn[i], "autostart") )
        {
149
            set_autoplay( boolValue(argv[i]) );
150
        }
151
        else if( !strcmp( argn[i], "fullscreen" )
152 153
              || !strcmp( argn[i], "allowfullscreen" )
              || !strcmp( argn[i], "fullscreenenabled" ) )
154
        {
155
            set_enable_fs( boolValue(argv[i]) );
156 157 158
        }
        else if( !strcmp( argn[i], "mute" ) )
        {
159
            b_mute = boolValue( argv[i] );
160
        }
161 162 163 164
        else if( !strcmp( argn[i], "volume" ) )
        {
            i_volume = atoi( argv[i] );
        }
165 166 167
        else if( !strcmp( argn[i], "loop")
              || !strcmp( argn[i], "autoloop") )
        {
168
            b_autoloop = boolValue(argv[i]);
169
        }
170 171
        else if( !strcmp( argn[i], "toolbar" )
              || !strcmp( argn[i], "controls") )
172
        {
173
            set_show_toolbar( boolValue(argv[i]) );
174
        }
175 176
        else if( !strcmp( argn[i], "bgcolor" ) )
        {
177
            set_bg_color( argv[i] );
178
        }
179 180 181 182
        else if( !strcmp( argn[i], "branding" ) )
        {
            set_enable_branding( boolValue(argv[i]) );
        }
183 184
    }

185 186
    try {
        VLC::Instance instance( ppsz_argc, ppsz_argv );
187
        m_player.open(instance);
188 189
    }
    catch (std::runtime_error&) {
190
        return NPERR_GENERIC_ERROR;
191
    }
192

193
    m_player.mlp().setPlaybackMode( b_autoloop ? libvlc_playback_mode_loop :
194 195 196 197
                                      libvlc_playback_mode_default );

    if( b_mute )
        m_player.get_mp().setMute( true );
198

199 200 201
    if( i_volume >= 0 && i_volume <= 200 )
        m_player.get_mp().setVolume( i_volume );

202 203 204 205 206
    /*
    ** fetch plugin base URL, which is the URL of the page containing the plugin
    ** this URL is used for making absolute URL from relative URL that may be
    ** passed as an MRL argument
    */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
207
    NPObject *plugin = NULL;
208 209 210 211 212 213 214 215 216 217

    if( NPERR_NO_ERROR == NPN_GetValue(p_browser, NPNVWindowNPObject, &plugin) )
    {
        /*
        ** is there a better way to get that info ?
        */
        static const char docLocHref[] = "document.location.href";
        NPString script;
        NPVariant result;

218 219
        script.UTF8Characters = docLocHref;
        script.UTF8Length = sizeof(docLocHref)-1;
220 221 222 223 224 225 226

        if( NPN_Evaluate(p_browser, plugin, &script, &result) )
        {
            if( NPVARIANT_IS_STRING(result) )
            {
                NPString &location = NPVARIANT_TO_STRING(result);

227
                psz_baseURL = (char *) malloc(location.UTF8Length+1);
228 229
                if( psz_baseURL )
                {
230 231
                    strncpy(psz_baseURL, location.UTF8Characters, location.UTF8Length);
                    psz_baseURL[location.UTF8Length] = '\0';
232 233 234 235 236 237 238 239 240 241
                }
            }
            NPN_ReleaseVariantValue(&result);
        }
        NPN_ReleaseObject(plugin);
    }

    if( psz_target )
    {
        // get absolute URL from src
242 243
        char *psz_absurl = getAbsoluteURL(psz_target);
        psz_target = psz_absurl ? psz_absurl : strdup(psz_target);
244 245 246
    }

    /* assign plugin script root class */
247 248
    /* new APIs */
    p_scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
249

250 251 252 253 254
    // Update the UI if required when we switch media
    m_player.mlp().eventManager().onNextItemSet([this](VLC::MediaPtr) {
        update_controls();
    });

255
    return NPERR_NO_ERROR;
256 257
}

258
VlcPluginBase::~VlcPluginBase()
259
{
260 261
    free(psz_baseURL);
    free(psz_target);
262 263
}

264
void VlcPluginBase::setWindow(const NPWindow &window)
265 266
{
    npwindow = window;
267
}
268

269 270 271 272 273 274 275
#if defined(XP_MACOSX)
NPError VlcPluginBase::get_root_layer(void *value)
{
    return NPERR_GENERIC_ERROR;
}
#endif

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
276
bool VlcPluginBase::handle_event(void *)
277 278 279 280
{
    return false;
}

281
template <typename... Args>
282 283
struct AsyncEventWrapper
{
284 285
    template <typename... PFArgs>
    AsyncEventWrapper(NPP b, NPObject* l, PFArgs&&... args)
286
        : browser( b )
287
        , listener( l )
288
        , args( std::make_tuple( std::forward<Args>( args )... ) )
289 290 291 292
    {
    }

    NPP browser;
293
    NPObject* listener;
294 295 296 297
    // If we do not decay Args here, we will end up declaring a tuple holding references
    // The tuple returned by make_tuple does that, but we end up converting from the correct tuple
    // type to an invalid tuple type, since we would end up using dangling references.
    std::tuple<typename std::decay<Args>::type...> args;
298 299 300
};

template <typename... Args>
301
static void invokeEvent( NPP browser, NPObject* listener, Args&&... args )
302
{
303
    auto wrapper = new AsyncEventWrapper<Args...>( browser, listener, std::forward<Args>( args )... );
304
    NPN_PluginThreadAsyncCall( browser, [](void* data) {
305 306
        auto w = reinterpret_cast<AsyncEventWrapper<Args...>*>( data );
        auto args = npapi::wrap( w->args );
307
        NPVariant result;
308
        if (NPN_InvokeDefault( w->browser, w->listener, reinterpret_cast<NPVariant*>( args.data() ), args.size(), &result ))
309 310 311 312 313 314 315 316 317 318 319
        {
            // "result" content is unspecified when invoke fails. Don't clean potential garbage
            NPN_ReleaseVariantValue( &result );
        }
        delete w;
    }, wrapper);
}

class CallbackClosure
{
public:
320
    CallbackClosure(NPP browser, npapi::Variant&& listener)
321 322 323 324 325 326
        : _browser( browser )
        , _listener( std::move( listener ) )
    {
    }

    CallbackClosure(const CallbackClosure&) = delete;
327 328

#ifndef _MSC_VER
329
    CallbackClosure(CallbackClosure&&) = default;
330 331 332 333 334 335 336
#else
    CallbackClosure(CallbackClosure&& c)
        : _browser( std::move(c._browser) )
        , _listener( std::move(c._listener) )
    {
    }
#endif
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393

    template <typename... Args>
    void operator()(Args&&... params) const
    {
        // This is expected to receive a copy of the listener
        invokeEvent( _browser, _listener, std::forward<Args>( params )... );
    }

    void operator()(VLC::MediaPtr) const
    {
        // Force Media to be ignored since we don't have a binding for it.
        // This is expected to receive a copy of the listener
        invokeEvent( _browser, _listener );
    }
private:
    NPP _browser;
    npapi::Variant _listener;
};

static struct vlcevents_t {
    const char* name;
    libvlc_event_type_t type;
} vlcevents[] = {
    { "MediaPlayerMediaChanged", libvlc_MediaPlayerMediaChanged },
    { "MediaPlayerNothingSpecial", libvlc_MediaPlayerNothingSpecial },
    { "MediaPlayerOpening", libvlc_MediaPlayerOpening },
    { "MediaPlayerBuffering", libvlc_MediaPlayerBuffering },
    { "MediaPlayerPlaying", libvlc_MediaPlayerPlaying },
    { "MediaPlayerPaused", libvlc_MediaPlayerPaused },
    { "MediaPlayerStopped", libvlc_MediaPlayerStopped },
    { "MediaPlayerForward", libvlc_MediaPlayerForward },
    { "MediaPlayerBackward", libvlc_MediaPlayerBackward },
    { "MediaPlayerEndReached", libvlc_MediaPlayerEndReached },
    { "MediaPlayerEncounteredError", libvlc_MediaPlayerEncounteredError },
    { "MediaPlayerTimeChanged", libvlc_MediaPlayerTimeChanged },
    { "MediaPlayerPositionChanged", libvlc_MediaPlayerPositionChanged },
    { "MediaPlayerSeekableChanged", libvlc_MediaPlayerSeekableChanged },
    { "MediaPlayerPausableChanged", libvlc_MediaPlayerPausableChanged },
    { "MediaPlayerTitleChanged", libvlc_MediaPlayerTitleChanged },
    { "MediaPlayerLengthChanged", libvlc_MediaPlayerLengthChanged },
};

void VlcPluginBase::subscribe(const char* eventName, npapi::Variant listener)
{
    auto event = std::find_if(std::begin(vlcevents), std::end(vlcevents), [eventName](const vlcevents_t& e) {
        return !strcmp( e.name, eventName);
    });
    if (event == std::end(vlcevents))
        return;

    auto listenerRaw = (NPObject*)listener;
    auto closure = CallbackClosure{ p_browser, std::move( listener ) };

    VLC::EventManager::RegisteredEvent e = nullptr;
    switch ( event->type )
    {
        case libvlc_MediaPlayerNothingSpecial:
394
            e = player().get_mp().eventManager().onNothingSpecial( std::move( closure ) );
395 396
            break;
        case libvlc_MediaPlayerOpening:
397
            e = player().get_mp().eventManager().onOpening( std::move( closure ) );
398 399
            break;
        case libvlc_MediaPlayerPlaying:
400
            e = player().get_mp().eventManager().onPlaying( std::move( closure ) );
401 402
            break;
        case libvlc_MediaPlayerPaused:
403
            e = player().get_mp().eventManager().onPaused( std::move( closure ) );
404 405
            break;
        case libvlc_MediaPlayerStopped:
406
            e = player().get_mp().eventManager().onStopped( std::move( closure ) );
407 408
            break;
        case libvlc_MediaPlayerForward:
409
            e = player().get_mp().eventManager().onForward( std::move( closure ) );
410 411
            break;
        case libvlc_MediaPlayerBackward:
412
            e = player().get_mp().eventManager().onBackward( std::move( closure ) );
413 414
            break;
        case libvlc_MediaPlayerEndReached:
415
            e = player().get_mp().eventManager().onEndReached( std::move( closure ) );
416 417
            break;
        case libvlc_MediaPlayerEncounteredError:
418
            e = player().get_mp().eventManager().onEncounteredError( std::move( closure ) );
419 420
            break;
        case libvlc_MediaPlayerBuffering:
421
            e = player().get_mp().eventManager().onBuffering( std::move( closure ) );
422 423
            break;
        case libvlc_MediaPlayerTimeChanged:
424
            e = player().get_mp().eventManager().onTimeChanged( std::move( closure ) );
425 426
            break;
        case libvlc_MediaPlayerMediaChanged:
427
            e = player().get_mp().eventManager().onMediaChanged( std::move( closure ) );
428 429
            break;
        case libvlc_MediaPlayerPositionChanged:
430
            e = player().get_mp().eventManager().onPositionChanged( std::move( closure ) );
431 432
            break;
        case libvlc_MediaPlayerSeekableChanged:
433
            e = player().get_mp().eventManager().onSeekableChanged( std::move( closure ) );
434 435
            break;
        case libvlc_MediaPlayerPausableChanged:
436
            e = player().get_mp().eventManager().onPausableChanged( std::move( closure ) );
437 438
            break;
        case libvlc_MediaPlayerTitleChanged:
439
            e = player().get_mp().eventManager().onTitleChanged( std::move( closure ) );
440 441
            break;
        case libvlc_MediaPlayerLengthChanged:
442
            e = player().get_mp().eventManager().onLengthChanged( std::move( closure ) );
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
            break;
        default:
            break;
    }
    if ( e != nullptr )
    {
        m_events.emplace_back( std::string(eventName), listenerRaw, e );
    }
}

void VlcPluginBase::unsubscribe(const char* eventName, npapi::Variant listener)
{
    auto event = std::find_if( begin( m_events ), end( m_events ), [eventName, listener](const decltype(m_events)::value_type e) {
        return std::get<0>( e ) == eventName && std::get<1>( e ) == listener;
    });
    if ( event == end( m_events ) )
        return;
    std::get<2>( *event )->unregister();
    m_events.erase( event );
}

464
/*****************************************************************************
465
 * VlcPluginBase methods
466
 *****************************************************************************/
467

468
char *VlcPluginBase::getAbsoluteURL(const char *url)
469
{
470
    if( NULL != url )
471
    {
472 473 474
        // check whether URL is already absolute
        const char *end=strchr(url, ':');
        if( (NULL != end) && (end != url) )
475
        {
476 477
            // validate protocol header
            const char *start = url;
478 479 480
            char c = *start;
            if( isalpha(c) )
            {
481
                ++start;
482 483 484 485 486 487 488 489 490 491 492 493 494 495
                while( start != end )
                {
                    c  = *start;
                    if( ! (isalnum(c)
                       || ('-' == c)
                       || ('+' == c)
                       || ('.' == c)
                       || ('/' == c)) ) /* VLC uses / to allow user to specify a demuxer */
                        // not valid protocol header, assume relative URL
                        goto relativeurl;
                    ++start;
                }
                /* we have a protocol header, therefore URL is absolute */
                return strdup(url);
496
            }
497
            // not a valid protocol header, assume relative URL
498
        }
499

500 501
relativeurl:

502 503 504
        if( psz_baseURL )
        {
            size_t baseLen = strlen(psz_baseURL);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
505
            char *href = (char *) malloc(baseLen+strlen(url)+1);
506 507 508
            if( href )
            {
                /* prepend base URL */
JP Dinger's avatar
JP Dinger committed
509
                memcpy(href, psz_baseURL, baseLen+1);
510 511 512 513 514 515 516 517 518 519 520 521 522 523

                /*
                ** relative url could be empty,
                ** in which case return base URL
                */
                if( '\0' == *url )
                    return href;

                /*
                ** locate pathname part of base URL
                */

                /* skip over protocol part  */
                char *pathstart = strchr(href, ':');
JP Dinger's avatar
JP Dinger committed
524
                char *pathend = href+baseLen;
525
                if( pathstart )
526 527 528
                {
                    if( '/' == *(++pathstart) )
                    {
529 530 531 532 533 534 535 536 537 538 539 540
                        if( '/' == *(++pathstart) )
                        {
                            ++pathstart;
                        }
                    }
                    /* skip over host part */
                    pathstart = strchr(pathstart, '/');
                    if( ! pathstart )
                    {
                        // no path, add a / past end of url (over '\0')
                        pathstart = pathend;
                        *pathstart = '/';
541 542
                    }
                }
543
                else
544
                {
545 546 547 548
                    /* baseURL is just a UNIX path */
                    if( '/' != *href )
                    {
                        /* baseURL is not an absolute path */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
549
                        free(href);
550 551 552
                        return NULL;
                    }
                    pathstart = href;
553 554 555 556 557 558 559 560 561 562
                }

                /* relative URL made of an absolute path ? */
                if( '/' == *url )
                {
                    /* replace path completely */
                    strcpy(pathstart, url);
                    return href;
                }

563
                /* find last path component and replace it */
564 565
                while( '/' != *pathend)
                    --pathend;
566 567 568 569 570 571 572 573 574 575 576 577

                /*
                ** if relative url path starts with one or more '../',
                ** factor them out of href so that we return a
                ** normalized URL
                */
                while( pathend != pathstart )
                {
                    const char *p = url;
                    if( '.' != *p )
                        break;
                    ++p;
578 579 580 581
                    if( '\0' == *p  )
                    {
                        /* relative url is just '.' */
                        url = p;
582
                        break;
583 584 585 586 587 588 589
                    }
                    if( '/' == *p  )
                    {
                        /* relative url starts with './' */
                        url = ++p;
                        continue;
                    }
590
                    if( '.' != *p )
591 592
                        break;
                    ++p;
593 594 595 596 597 598
                    if( '\0' == *p )
                    {
                        /* relative url is '..' */
                    }
                    else
                    {
599
                        if( '/' != *p )
600 601 602 603
                            break;
                        /* relative url starts with '../' */
                        ++p;
                    }
604
                    url = p;
605 606 607 608 609
                    do
                    {
                        --pathend;
                    }
                    while( '/' != *pathend );
610
                }
611 612
                /* skip over '/' separator */
                ++pathend;
613
                /* concatenate remaining base URL and relative URL */
614
                strcpy(pathend, url);
615 616 617
            }
            return href;
        }
618
    }
619 620
    return NULL;
}
621

622
void VlcPluginBase::control_handler(vlc_toolbar_clicked_t clicked)
623
{
624
    switch( clicked )
625
    {
626 627
        case clicked_Play:
        {
628
            player().play();
629 630
        }
        break;
631

632 633
        case clicked_Pause:
        {
634
            player().get_mp().pause();
635 636
        }
        break;
637

638 639
        case clicked_Stop:
        {
640
            player().get_mp().stop();
641 642
        }
        break;
643

644 645
        case clicked_Fullscreen:
        {
646
            toggle_fullscreen();
647 648
        }
        break;
649

650 651 652 653 654 655 656 657 658
        case clicked_Mute:
        case clicked_Unmute:
#if 0
        {
            if( p_md )
                libvlc_audio_toggle_mute( p_md );
        }
#endif
        break;
659

660 661 662 663 664 665 666 667
        case clicked_timeline:
#if 0
        {
            /* if a movie is loaded */
            if( p_md )
            {
                int64_t f_length;
                f_length = libvlc_media_player_get_length( p_md ) / 100;
668

669 670
                f_length = (float)f_length *
                        ( ((float)i_xPos-4.0 ) / ( ((float)i_width-8.0)/100) );
671

672 673 674
                libvlc_media_player_set_time( p_md, f_length );
            }
        }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
675
#endif
676
        break;
677

678 679 680 681 682
        case clicked_Time:
        {
            /* Not implemented yet*/
        }
        break;
683

684 685 686 687
        default: /* button_Unknown */
            fprintf(stderr, "button Unknown!\n");
        break;
    }
688
}
689 690 691 692

// Verifies the version of the NPAPI.
// The eventListeners use a NPAPI function available
// since Gecko 1.9.
693
bool VlcPluginBase::canUseEventListener()
694 695 696 697 698 699 700 701 702 703 704
{
    int plugin_major, plugin_minor;
    int browser_major, browser_minor;

    NPN_Version(&plugin_major, &plugin_minor,
                &browser_major, &browser_minor);

    if (browser_minor >= 19 || browser_major > 0)
        return true;
    return false;
}
705