vlcplugin_base.cpp 21.7 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
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

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

41
#include "npruntime/npolibvlc.h"
42

43
#include <cctype>
44

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

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

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

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

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

80
    /* locate VLC module path */
Felix Paul Kühne's avatar
Felix Paul Kühne committed
81
#ifdef XP_WIN
82 83 84 85 86
    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 )
87
    {
88 89 90 91 92
         if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
                              (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
         {
             if( i_type == REG_SZ )
             {
93
                 strcat( p_data, "\\plugins" );
94 95
                 ppsz_argv[ppsz_argc++] = "--plugin-path";
                 ppsz_argv[ppsz_argc++] = p_data;
96 97 98
             }
         }
         RegCloseKey( h_key );
99
    }
100
    ppsz_argv[ppsz_argc++] = "--no-one-instance";
101

102 103
#endif
#ifdef XP_MACOSX
104
    ppsz_argv[ppsz_argc++] = "--vout=caopengllayer";
105 106 107
    ppsz_argv[ppsz_argc++] = "--scaletempo-stride=30";
    ppsz_argv[ppsz_argc++] = "--scaletempo-overlap=0,2";
    ppsz_argv[ppsz_argc++] = "--scaletempo-search=14";
108
    ppsz_argv[ppsz_argc++] = "--auhal-volume=256";
109 110
    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
111
#endif
112

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

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

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

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

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

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

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

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

201 202 203 204 205
    /*
    ** 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
206
    NPObject *plugin = NULL;
207 208 209 210 211 212 213 214 215 216

    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;

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

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

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

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

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

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

254
    return NPERR_NO_ERROR;
255 256
}

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

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

268 269 270 271 272 273 274
#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
275
bool VlcPluginBase::handle_event(void *)
276 277 278 279
{
    return false;
}

280 281
struct AsyncEventWrapper
{
282
    AsyncEventWrapper(NPP b, NPObject* l, npapi::VariantArray&& a)
283
        : browser( b )
284
        , listener( l )
285 286 287 288 289
        , args( std::move( a ) )
    {
    }

    NPP browser;
290
    NPObject* listener;
291 292 293 294
    npapi::VariantArray args;
};

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

class CallbackClosure
{
public:
313
    CallbackClosure(NPP browser, npapi::Variant&& listener)
314 315 316 317 318 319
        : _browser( browser )
        , _listener( std::move( listener ) )
    {
    }

    CallbackClosure(const CallbackClosure&) = delete;
320 321

#ifndef _MSC_VER
322
    CallbackClosure(CallbackClosure&&) = default;
323 324 325 326 327 328 329
#else
    CallbackClosure(CallbackClosure&& c)
        : _browser( std::move(c._browser) )
        , _listener( std::move(c._listener) )
    {
    }
#endif
330 331 332 333 334 335 336 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

    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:
387
            e = player().get_mp().eventManager().onNothingSpecial( std::move( closure ) );
388 389
            break;
        case libvlc_MediaPlayerOpening:
390
            e = player().get_mp().eventManager().onOpening( std::move( closure ) );
391 392
            break;
        case libvlc_MediaPlayerPlaying:
393
            e = player().get_mp().eventManager().onPlaying( std::move( closure ) );
394 395
            break;
        case libvlc_MediaPlayerPaused:
396
            e = player().get_mp().eventManager().onPaused( std::move( closure ) );
397 398
            break;
        case libvlc_MediaPlayerStopped:
399
            e = player().get_mp().eventManager().onStopped( std::move( closure ) );
400 401
            break;
        case libvlc_MediaPlayerForward:
402
            e = player().get_mp().eventManager().onForward( std::move( closure ) );
403 404
            break;
        case libvlc_MediaPlayerBackward:
405
            e = player().get_mp().eventManager().onBackward( std::move( closure ) );
406 407
            break;
        case libvlc_MediaPlayerEndReached:
408
            e = player().get_mp().eventManager().onEndReached( std::move( closure ) );
409 410
            break;
        case libvlc_MediaPlayerEncounteredError:
411
            e = player().get_mp().eventManager().onEncounteredError( std::move( closure ) );
412 413
            break;
        case libvlc_MediaPlayerBuffering:
414
            e = player().get_mp().eventManager().onBuffering( std::move( closure ) );
415 416
            break;
        case libvlc_MediaPlayerTimeChanged:
417
            e = player().get_mp().eventManager().onTimeChanged( std::move( closure ) );
418 419
            break;
        case libvlc_MediaPlayerMediaChanged:
420
            e = player().get_mp().eventManager().onMediaChanged( std::move( closure ) );
421 422
            break;
        case libvlc_MediaPlayerPositionChanged:
423
            e = player().get_mp().eventManager().onPositionChanged( std::move( closure ) );
424 425
            break;
        case libvlc_MediaPlayerSeekableChanged:
426
            e = player().get_mp().eventManager().onSeekableChanged( std::move( closure ) );
427 428
            break;
        case libvlc_MediaPlayerPausableChanged:
429
            e = player().get_mp().eventManager().onPausableChanged( std::move( closure ) );
430 431
            break;
        case libvlc_MediaPlayerTitleChanged:
432
            e = player().get_mp().eventManager().onTitleChanged( std::move( closure ) );
433 434
            break;
        case libvlc_MediaPlayerLengthChanged:
435
            e = player().get_mp().eventManager().onLengthChanged( std::move( closure ) );
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
            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 );
}

457
/*****************************************************************************
458
 * VlcPluginBase methods
459
 *****************************************************************************/
460

461
char *VlcPluginBase::getAbsoluteURL(const char *url)
462
{
463
    if( NULL != url )
464
    {
465 466 467
        // check whether URL is already absolute
        const char *end=strchr(url, ':');
        if( (NULL != end) && (end != url) )
468
        {
469 470
            // validate protocol header
            const char *start = url;
471 472 473
            char c = *start;
            if( isalpha(c) )
            {
474
                ++start;
475 476 477 478 479 480 481 482 483 484 485 486 487 488
                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);
489
            }
490
            // not a valid protocol header, assume relative URL
491
        }
492

493 494
relativeurl:

495 496 497
        if( psz_baseURL )
        {
            size_t baseLen = strlen(psz_baseURL);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
498
            char *href = (char *) malloc(baseLen+strlen(url)+1);
499 500 501
            if( href )
            {
                /* prepend base URL */
JP Dinger's avatar
JP Dinger committed
502
                memcpy(href, psz_baseURL, baseLen+1);
503 504 505 506 507 508 509 510 511 512 513 514 515 516

                /*
                ** 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
517
                char *pathend = href+baseLen;
518
                if( pathstart )
519 520 521
                {
                    if( '/' == *(++pathstart) )
                    {
522 523 524 525 526 527 528 529 530 531 532 533
                        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 = '/';
534 535
                    }
                }
536
                else
537
                {
538 539 540 541
                    /* baseURL is just a UNIX path */
                    if( '/' != *href )
                    {
                        /* baseURL is not an absolute path */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
542
                        free(href);
543 544 545
                        return NULL;
                    }
                    pathstart = href;
546 547 548 549 550 551 552 553 554 555
                }

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

556
                /* find last path component and replace it */
557 558
                while( '/' != *pathend)
                    --pathend;
559 560 561 562 563 564 565 566 567 568 569 570

                /*
                ** 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;
571 572 573 574
                    if( '\0' == *p  )
                    {
                        /* relative url is just '.' */
                        url = p;
575
                        break;
576 577 578 579 580 581 582
                    }
                    if( '/' == *p  )
                    {
                        /* relative url starts with './' */
                        url = ++p;
                        continue;
                    }
583
                    if( '.' != *p )
584 585
                        break;
                    ++p;
586 587 588 589 590 591
                    if( '\0' == *p )
                    {
                        /* relative url is '..' */
                    }
                    else
                    {
592
                        if( '/' != *p )
593 594 595 596
                            break;
                        /* relative url starts with '../' */
                        ++p;
                    }
597
                    url = p;
598 599 600 601 602
                    do
                    {
                        --pathend;
                    }
                    while( '/' != *pathend );
603
                }
604 605
                /* skip over '/' separator */
                ++pathend;
606
                /* concatenate remaining base URL and relative URL */
607
                strcpy(pathend, url);
608 609 610
            }
            return href;
        }
611
    }
612 613
    return NULL;
}
614

615
void VlcPluginBase::control_handler(vlc_toolbar_clicked_t clicked)
616
{
617
    switch( clicked )
618
    {
619 620
        case clicked_Play:
        {
621
            player().play();
622 623
        }
        break;
624

625 626
        case clicked_Pause:
        {
627
            player().get_mp().pause();
628 629
        }
        break;
630

631 632
        case clicked_Stop:
        {
633
            player().get_mp().stop();
634 635
        }
        break;
636

637 638
        case clicked_Fullscreen:
        {
639
            toggle_fullscreen();
640 641
        }
        break;
642

643 644 645 646 647 648 649 650 651
        case clicked_Mute:
        case clicked_Unmute:
#if 0
        {
            if( p_md )
                libvlc_audio_toggle_mute( p_md );
        }
#endif
        break;
652

653 654 655 656 657 658 659 660
        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;
661

662 663
                f_length = (float)f_length *
                        ( ((float)i_xPos-4.0 ) / ( ((float)i_width-8.0)/100) );
664

665 666 667
                libvlc_media_player_set_time( p_md, f_length );
            }
        }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
668
#endif
669
        break;
670

671 672 673 674 675
        case clicked_Time:
        {
            /* Not implemented yet*/
        }
        break;
676

677 678 679 680
        default: /* button_Unknown */
            fprintf(stderr, "button Unknown!\n");
        break;
    }
681
}
682 683 684 685

// Verifies the version of the NPAPI.
// The eventListeners use a NPAPI function available
// since Gecko 1.9.
686
bool VlcPluginBase::canUseEventListener()
687 688 689 690 691 692 693 694 695 696 697
{
    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;
}
698