vlcplugin.cpp 28.3 KB
Newer Older
1
/*****************************************************************************
2
 * vlcplugin.cpp: a VLC plugin for Mozilla
3
 *****************************************************************************
4
 * Copyright (C) 2002-2009 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
8
 *          Damien Fouilleul <damienf.fouilleul@laposte.net>
9
 *          Jean-Paul Saman <jpsaman@videolan.org>
10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
29 30 31 32 33 34
#include "config.h"

#ifdef HAVE_MOZILLA_CONFIG_H
#   include <mozilla-config.h>
#endif

35
#include "vlcplugin.h"
36
#include "control/npolibvlc.h"
37

38 39
#include <ctype.h>

40
/*****************************************************************************
41
 * VlcPlugin constructor and destructor
42
 *****************************************************************************/
43 44 45
VlcPlugin::VlcPlugin( NPP instance, uint16 mode ) :
    i_npmode(mode),
    b_stream(0),
46
    b_autoplay(1),
47
    b_toolbar(0),
48
    psz_text(NULL),
49
    psz_target(NULL),
50
    playlist_index(-1),
51
    libvlc_instance(NULL),
52 53
    libvlc_media_list(NULL),
    libvlc_media_player(NULL),
54
    p_scriptClass(NULL),
55 56 57 58 59 60 61 62
    p_browser(instance),
    psz_baseURL(NULL)
#if XP_WIN
    ,pf_wndproc(NULL)
#endif
#if XP_UNIX
    ,i_width((unsigned)-1)
    ,i_height((unsigned)-1)
63 64
    ,i_tb_width(0)
    ,i_tb_height(0)
65
    ,i_last_position(0)
66 67 68 69 70 71 72 73
    ,p_btnPlay(NULL)
    ,p_btnPause(NULL)
    ,p_btnStop(NULL)
    ,p_btnMute(NULL)
    ,p_btnUnmute(NULL)
    ,p_btnFullscreen(NULL)
    ,p_btnTime(NULL)
    ,p_timeline(NULL)
74
#endif
75
{
76
    memset(&npwindow, 0, sizeof(NPWindow));
77
#if XP_UNIX
78 79
    memset(&npvideo, 0, sizeof(Window));
    memset(&npcontrol, 0, sizeof(Window));
80
#endif
81 82
}

83
static bool boolValue(const char *value) {
84
    return ( !strcmp(value, "1") ||
85 86 87
             !strcasecmp(value, "true") ||
             !strcasecmp(value, "yes") );
}
88

89
NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
90
{
91
    /* prepare VLC command line */
92
    const char *ppsz_argv[32];
93
    int ppsz_argc = 0;
94

95 96 97 98
#ifndef NDEBUG
    ppsz_argv[ppsz_argc++] = "--no-plugins-cache";
#endif

99 100
    /* locate VLC module path */
#ifdef XP_MACOSX
101 102
    ppsz_argv[ppsz_argc++] = "--plugin-path=/Library/Internet\\ Plug-Ins/VLC\\ Plugin.plugin/Contents/MacOS/modules";
    ppsz_argv[ppsz_argc++] = "--vout=macosx";
103 104 105 106 107 108
#elif defined(XP_WIN)
    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 )
109
    {
110 111 112 113 114
         if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
                              (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
         {
             if( i_type == REG_SZ )
             {
115
                 strcat( p_data, "\\plugins" );
116 117
                 ppsz_argv[ppsz_argc++] = "--plugin-path";
                 ppsz_argv[ppsz_argc++] = p_data;
118 119 120
             }
         }
         RegCloseKey( h_key );
121
    }
122
    ppsz_argv[ppsz_argc++] = "--no-one-instance";
123

124
#endif /* XP_MACOSX */
125

126 127 128 129
    /* common settings */
    ppsz_argv[ppsz_argc++] = "-vv";
    ppsz_argv[ppsz_argc++] = "--no-stats";
    ppsz_argv[ppsz_argc++] = "--no-media-library";
130
    ppsz_argv[ppsz_argc++] = "--ignore-config";
131
    ppsz_argv[ppsz_argc++] = "--intf=dummy";
132 133
    ppsz_argv[ppsz_argc++] = "--no-video-title-show";

134
    const char *progid = NULL;
135 136 137 138

    /* parse plugin arguments */
    for( int i = 0; i < argc ; i++ )
    {
139
       /* fprintf(stderr, "argn=%s, argv=%s\n", argn[i], argv[i]); */
140 141 142 143 144 145 146 147

        if( !strcmp( argn[i], "target" )
         || !strcmp( argn[i], "mrl")
         || !strcmp( argn[i], "filename")
         || !strcmp( argn[i], "src") )
        {
            psz_target = argv[i];
        }
148 149 150 151
        else if( !strcmp( argn[i], "text" ) )
        {
            psz_text = strdup( argv[i] );
        }
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
        else if( !strcmp( argn[i], "autoplay")
              || !strcmp( argn[i], "autostart") )
        {
            b_autoplay = boolValue(argv[i]);
        }
        else if( !strcmp( argn[i], "fullscreen" ) )
        {
            if( boolValue(argv[i]) )
            {
                ppsz_argv[ppsz_argc++] = "--fullscreen";
            }
            else
            {
                ppsz_argv[ppsz_argc++] = "--no-fullscreen";
            }
        }
        else if( !strcmp( argn[i], "mute" ) )
        {
            if( boolValue(argv[i]) )
            {
172
                ppsz_argv[ppsz_argc++] = "--volume=0";
173 174 175 176 177 178 179 180 181
            }
        }
        else if( !strcmp( argn[i], "loop")
              || !strcmp( argn[i], "autoloop") )
        {
            if( boolValue(argv[i]) )
            {
                ppsz_argv[ppsz_argc++] = "--loop";
            }
182 183
            else
            {
184 185 186
                ppsz_argv[ppsz_argc++] = "--no-loop";
            }
        }
187 188
        else if( !strcmp( argn[i], "version")
              || !strcmp( argn[i], "progid") )
189
        {
190
            progid = argv[i];
191
        }
192
        else if( !strcmp( argn[i], "toolbar" ) )
193
        {
194
/* FIXME: Remove this when toolbar functionality has been implemented on
195 196
 * MacOS X and Win32 for Firefox/Mozilla/Safari. */
#ifdef XP_UNIX
197
            b_toolbar = boolValue(argv[i]);
198
#endif
199
        }
200 201
    }

202 203
    libvlc_exception_t ex;
    libvlc_exception_init(&ex);
204

205
    libvlc_instance = libvlc_new(ppsz_argc, ppsz_argv, &ex);
206 207 208 209 210 211 212
    if( libvlc_exception_raised(&ex) )
    {
        libvlc_exception_clear(&ex);
        return NPERR_GENERIC_ERROR;
    }

    libvlc_media_list = libvlc_media_list_new(libvlc_instance,&ex);
213
    if( libvlc_exception_raised(&ex) )
214
    {
215
        libvlc_exception_clear(&ex);
216 217 218 219 220 221 222 223
        return NPERR_GENERIC_ERROR;
    }

    /*
    ** 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
224
    NPObject *plugin = NULL;
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243

    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;

        script.utf8characters = docLocHref;
        script.utf8length = sizeof(docLocHref)-1;

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

Jean-Paul Saman's avatar
Jean-Paul Saman committed
244
                psz_baseURL = (char *) malloc(location.utf8length+1);
245 246 247 248 249 250 251 252 253 254 255 256 257 258
                if( psz_baseURL )
                {
                    strncpy(psz_baseURL, location.utf8characters, location.utf8length);
                    psz_baseURL[location.utf8length] = '\0';
                }
            }
            NPN_ReleaseVariantValue(&result);
        }
        NPN_ReleaseObject(plugin);
    }

    if( psz_target )
    {
        // get absolute URL from src
259 260
        char *psz_absurl = getAbsoluteURL(psz_target);
        psz_target = psz_absurl ? psz_absurl : strdup(psz_target);
261 262 263
    }

    /* assign plugin script root class */
264 265
    /* new APIs */
    p_scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
266 267

    return NPERR_NO_ERROR;
268 269
}

270
VlcPlugin::~VlcPlugin()
271
{
272 273
    free(psz_baseURL);
    free(psz_target);
274
    free(psz_text);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
275

276 277 278 279
    if( libvlc_media_player )
        libvlc_media_player_release( libvlc_media_player );
    if( libvlc_media_list )
        libvlc_media_list_release( libvlc_media_list );
280
    if( libvlc_instance )
281
        libvlc_release(libvlc_instance);
282 283
}

284 285 286 287 288 289 290
/*****************************************************************************
 * VlcPlugin playlist replacement methods
 *****************************************************************************/
void VlcPlugin::set_player_window( libvlc_exception_t *ex )
{
#ifdef XP_UNIX
    libvlc_media_player_set_xwindow(libvlc_media_player,
291
                                    (libvlc_drawable_t)getVideoWindow(),
292 293 294 295 296 297 298
                                    ex);
#endif
#ifdef XP_MACOSX
    // XXX FIXME insert appropriate call here
#endif
#ifdef XP_WIN
    libvlc_media_player_set_hwnd(libvlc_media_player,
299
                                 getWindow().window,
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
                                 ex);
#endif
}

int VlcPlugin::playlist_add( const char *mrl, libvlc_exception_t *ex )
{
    int item = -1;
    libvlc_media_t *p_m = libvlc_media_new(libvlc_instance,mrl,ex);
    if( libvlc_exception_raised(ex) )
        return -1;

    libvlc_media_list_lock(libvlc_media_list);
    libvlc_media_list_add_media(libvlc_media_list,p_m,ex);
    if( !libvlc_exception_raised(ex) )
        item = libvlc_media_list_count(libvlc_media_list,ex)-1;
    libvlc_media_list_unlock(libvlc_media_list);

    libvlc_media_release(p_m);

    return item;
}

int VlcPlugin::playlist_add_extended_untrusted( const char *mrl, const char *name,
                    int optc, const char **optv, libvlc_exception_t *ex )
{
    libvlc_media_t *p_m = libvlc_media_new(libvlc_instance, mrl,ex);
    int item = -1;
    if( libvlc_exception_raised(ex) )
        return -1;

    for( int i = 0; i < optc; ++i )
    {
332
        libvlc_media_add_option_flag(p_m, optv[i], libvlc_media_option_unique, ex);
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 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
        if( libvlc_exception_raised(ex) )
        {
            libvlc_media_release(p_m);
            return -1;
        }
    }

    libvlc_media_list_lock(libvlc_media_list);
    libvlc_media_list_add_media(libvlc_media_list,p_m,ex);
    if( !libvlc_exception_raised(ex) )
        item = libvlc_media_list_count(libvlc_media_list,ex)-1;
    libvlc_media_list_unlock(libvlc_media_list);
    libvlc_media_release(p_m);

    return item;
}

bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
{
    libvlc_media_t *p_m = NULL;

    libvlc_media_list_lock(libvlc_media_list);

    int count = libvlc_media_list_count(libvlc_media_list,ex);
    if( libvlc_exception_raised(ex) )
        goto bad_unlock;

    if( idx<0||idx>=count )
        goto bad_unlock;

    playlist_index = idx;

    p_m = libvlc_media_list_item_at_index(libvlc_media_list,playlist_index,ex);
    libvlc_media_list_unlock(libvlc_media_list);

    if( libvlc_exception_raised(ex) )
        return false;

    if( libvlc_media_player )
    {
        libvlc_media_player_release( libvlc_media_player );
        libvlc_media_player = NULL;
    }

    libvlc_media_player = libvlc_media_player_new_from_media(p_m,ex);
    if( libvlc_media_player )
        set_player_window(ex);

    libvlc_media_release( p_m );
    return !libvlc_exception_raised(ex);

bad_unlock:
    libvlc_media_list_unlock(libvlc_media_list);
    return false;
}

void VlcPlugin::playlist_delete_item( int idx, libvlc_exception_t *ex )
{
    libvlc_media_list_lock(libvlc_media_list);
    libvlc_media_list_remove_index(libvlc_media_list,idx,ex);
    libvlc_media_list_unlock(libvlc_media_list);
}

void VlcPlugin::playlist_clear( libvlc_exception_t *ex )
{
    if( libvlc_media_list )
        libvlc_media_list_release(libvlc_media_list);
    libvlc_media_list = libvlc_media_list_new(getVLC(),ex);
}

int VlcPlugin::playlist_count( libvlc_exception_t *ex )
{
    int items_count = 0;
    libvlc_media_list_lock(libvlc_media_list);
    items_count = libvlc_media_list_count(libvlc_media_list,ex);
    libvlc_media_list_unlock(libvlc_media_list);
    return items_count;
}

void VlcPlugin::toggle_fullscreen( libvlc_exception_t *ex )
{
    if( playlist_isplaying(ex) )
        libvlc_toggle_fullscreen(libvlc_media_player,ex);
}
void VlcPlugin::set_fullscreen( int yes, libvlc_exception_t *ex )
{
    if( playlist_isplaying(ex) )
        libvlc_set_fullscreen(libvlc_media_player,yes,ex);
}
int  VlcPlugin::get_fullscreen( libvlc_exception_t *ex )
{
    int r = 0;
    if( playlist_isplaying(ex) )
        r = libvlc_get_fullscreen(libvlc_media_player,ex);
    return r;
}

Jean-Paul Saman's avatar
Jean-Paul Saman committed
430
bool  VlcPlugin::player_has_vout( libvlc_exception_t *ex )
431
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
432
    bool r = false;
433 434 435 436 437
    if( playlist_isplaying(ex) )
        r = libvlc_media_player_has_vout(libvlc_media_player, ex);
    return r;
}

438 439 440
/*****************************************************************************
 * VlcPlugin methods
 *****************************************************************************/
441

442
char *VlcPlugin::getAbsoluteURL(const char *url)
443
{
444
    if( NULL != url )
445
    {
446 447 448
        // check whether URL is already absolute
        const char *end=strchr(url, ':');
        if( (NULL != end) && (end != url) )
449
        {
450 451
            // validate protocol header
            const char *start = url;
452 453 454
            char c = *start;
            if( isalpha(c) )
            {
455
                ++start;
456 457 458 459 460 461 462 463 464 465 466 467 468 469
                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);
470
            }
471
            // not a valid protocol header, assume relative URL
472
        }
473

474 475
relativeurl:

476 477 478
        if( psz_baseURL )
        {
            size_t baseLen = strlen(psz_baseURL);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
479
            char *href = (char *) malloc(baseLen+strlen(url)+1);
480 481 482
            if( href )
            {
                /* prepend base URL */
JP Dinger's avatar
JP Dinger committed
483
                memcpy(href, psz_baseURL, baseLen+1);
484 485 486 487 488 489 490 491 492 493 494 495 496 497

                /*
                ** 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
498
                char *pathend = href+baseLen;
499
                if( pathstart )
500 501 502
                {
                    if( '/' == *(++pathstart) )
                    {
503 504 505 506 507 508 509 510 511 512 513 514
                        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 = '/';
515 516
                    }
                }
517
                else
518
                {
519 520 521 522
                    /* baseURL is just a UNIX path */
                    if( '/' != *href )
                    {
                        /* baseURL is not an absolute path */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
523
                        free(href);
524 525 526
                        return NULL;
                    }
                    pathstart = href;
527 528 529 530 531 532 533 534 535 536
                }

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

537
                /* find last path component and replace it */
538 539
                while( '/' != *pathend)
                    --pathend;
540 541 542 543 544 545 546 547 548 549 550 551

                /*
                ** 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;
552 553 554 555
                    if( '\0' == *p  )
                    {
                        /* relative url is just '.' */
                        url = p;
556
                        break;
557 558 559 560 561 562 563
                    }
                    if( '/' == *p  )
                    {
                        /* relative url starts with './' */
                        url = ++p;
                        continue;
                    }
564
                    if( '.' != *p )
565 566
                        break;
                    ++p;
567 568 569 570 571 572
                    if( '\0' == *p )
                    {
                        /* relative url is '..' */
                    }
                    else
                    {
573
                        if( '/' != *p )
574 575 576 577
                            break;
                        /* relative url starts with '../' */
                        ++p;
                    }
578
                    url = p;
579 580 581 582 583
                    do
                    {
                        --pathend;
                    }
                    while( '/' != *pathend );
584
                }
585 586
                /* skip over '/' separator */
                ++pathend;
587
                /* concatenate remaining base URL and relative URL */
588
                strcpy(pathend, url);
589 590 591
            }
            return href;
        }
592
    }
593 594
    return NULL;
}
595

596 597 598 599 600 601 602 603 604 605
#if XP_UNIX
int  VlcPlugin::setSize(unsigned width, unsigned height)
{
    int diff = (width != i_width) || (height != i_height);

    i_width = width;
    i_height = height;

    /* return size */
    return diff;
606 607
}

608
#define BTN_SPACE ((unsigned int)4)
609 610 611 612
void VlcPlugin::showToolbar()
{
    const NPWindow& window = getWindow();
    Window control = getControlWindow();
613
    Window video = getVideoWindow();
614
    Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
615
    unsigned int i_height = 0, i_width = BTN_SPACE;
616 617

    /* load icons */
618 619 620
    if( !p_btnPlay )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/play.xpm",
                            &p_btnPlay, NULL, NULL);
621
    if( p_btnPlay )
622 623 624
    {
        i_height = __MAX( i_height, p_btnPlay->height );
    }
625 626 627
    if( !p_btnPause )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/pause.xpm",
                            &p_btnPause, NULL, NULL);
628
    if( p_btnPause )
629 630 631
    {
        i_height = __MAX( i_height, p_btnPause->height );
    }
632 633
    i_width += __MAX( p_btnPause->width, p_btnPlay->width );

634 635 636
    if( !p_btnStop )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/stop.xpm",
                            &p_btnStop, NULL, NULL );
637
    if( p_btnStop )
638 639
    {
        i_height = __MAX( i_height, p_btnStop->height );
640
        i_width += BTN_SPACE + p_btnStop->width;
641
    }
642 643 644
    if( !p_timeline )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/time_line.xpm",
                            &p_timeline, NULL, NULL);
645
    if( p_timeline )
646 647
    {
        i_height = __MAX( i_height, p_timeline->height );
648
        i_width += BTN_SPACE + p_timeline->width;
649
    }
650 651 652
    if( !p_btnTime )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/time_icon.xpm",
                            &p_btnTime, NULL, NULL);
653
    if( p_btnTime )
654 655
    {
        i_height = __MAX( i_height, p_btnTime->height );
656
        i_width += BTN_SPACE + p_btnTime->width;
657
    }
658 659 660
    if( !p_btnFullscreen )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/fullscreen.xpm",
                            &p_btnFullscreen, NULL, NULL);
661
    if( p_btnFullscreen )
662 663
    {
        i_height = __MAX( i_height, p_btnFullscreen->height );
664
        i_width += BTN_SPACE + p_btnFullscreen->width;
665
    }
666 667 668
    if( !p_btnMute )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/volume_max.xpm",
                            &p_btnMute, NULL, NULL);
669
    if( p_btnMute )
670 671 672
    {
        i_height = __MAX( i_height, p_btnMute->height );
    }
673 674 675
    if( !p_btnUnmute )
        XpmReadFileToImage( p_display, DATA_PATH "/mozilla/volume_mute.xpm",
                            &p_btnUnmute, NULL, NULL);
676
    if( p_btnUnmute )
677 678 679
    {
        i_height = __MAX( i_height, p_btnUnmute->height );
    }
680 681
    i_width += BTN_SPACE + __MAX( p_btnUnmute->width, p_btnMute->width );

682
    setToolbarSize( i_width, i_height );
683 684 685 686

    if( !p_btnPlay || !p_btnPause || !p_btnStop || !p_timeline ||
        !p_btnTime || !p_btnFullscreen || !p_btnMute || !p_btnUnmute )
        fprintf(stderr, "Error: some button images not found in %s\n", DATA_PATH );
687 688 689 690 691 692 693 694 695

    /* reset panels position and size */
    /* XXX  use i_width */
    XResizeWindow( p_display, video, window.width, window.height - i_height);
    XMoveWindow( p_display, control, 0, window.height - i_height );
    XResizeWindow( p_display, control, window.width, i_height -1);

    b_toolbar = 1; /* says toolbar is now shown */
    redrawToolbar();
696 697 698 699
}

void VlcPlugin::hideToolbar()
{
700 701 702 703 704
    const NPWindow& window = getWindow();
    Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
    Window control = getControlWindow();
    Window video = getVideoWindow();

705 706
    i_tb_width = i_tb_height = 0;

707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
    if( p_btnPlay )  XDestroyImage( p_btnPlay );
    if( p_btnPause ) XDestroyImage( p_btnPause );
    if( p_btnStop )  XDestroyImage( p_btnStop );
    if( p_timeline ) XDestroyImage( p_timeline );
    if( p_btnTime )  XDestroyImage( p_btnTime );
    if( p_btnFullscreen ) XDestroyImage( p_btnFullscreen );
    if( p_btnMute )  XDestroyImage( p_btnMute );
    if( p_btnUnmute ) XDestroyImage( p_btnUnmute );

    p_btnPlay = NULL;
    p_btnPause = NULL;
    p_btnStop = NULL;
    p_timeline = NULL;
    p_btnTime = NULL;
    p_btnFullscreen = NULL;
    p_btnMute = NULL;
    p_btnUnmute = NULL;
724 725 726 727 728 729 730 731 732

    /* reset panels position and size */
    /* XXX  use i_width */
    XResizeWindow( p_display, video, window.width, window.height );
    XMoveWindow( p_display, control, 0, window.height-1 );
    XResizeWindow( p_display, control, window.width, 1 );

    b_toolbar = 0; /* says toolbar is now hidden */
    redrawToolbar();
733 734 735 736 737
}

void VlcPlugin::redrawToolbar()
{
    libvlc_exception_t ex;
738
    int is_playing = 0;
739
    bool b_mute = false;
740
    unsigned int dst_x, dst_y;
741 742
    GC gc;
    XGCValues gcv;
743
    unsigned int i_tb_width, i_tb_height;
744

745 746 747 748
    /* This method does nothing if toolbar is hidden. */
    if( !b_toolbar )
        return;

749 750 751 752
    const NPWindow& window = getWindow();
    Window control = getControlWindow();
    Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;

753 754
    getToolbarSize( &i_tb_width, &i_tb_height );

755 756 757 758 759 760 761 762 763 764
    libvlc_exception_init( &ex );

    /* get mute info */
    b_mute = libvlc_audio_get_mute( getVLC(), &ex );
    libvlc_exception_clear( &ex );

    gcv.foreground = BlackPixel( p_display, 0 );
    gc = XCreateGC( p_display, control, GCForeground, &gcv );

    XFillRectangle( p_display, control, gc,
765
                    0, 0, window.width, i_tb_height );
766 767 768 769
    gcv.foreground = WhitePixel( p_display, 0 );
    XChangeGC( p_display, gc, GCForeground, &gcv );

    /* position icons */
770 771
    dst_x = BTN_SPACE;
    dst_y = i_tb_height >> 1; /* baseline = vertical middle */
772

773
    if( p_btnPause && (is_playing == 1) )
774
    {
775 776
        XPutImage( p_display, control, gc, p_btnPause, 0, 0, dst_x,
                   dst_y - (p_btnPause->height >> 1),
777
                   p_btnPause->width, p_btnPause->height );
778
        dst_x += BTN_SPACE + p_btnPause->width;
779
    }
780
    else if( p_btnPlay )
781
    {
782 783
        XPutImage( p_display, control, gc, p_btnPlay, 0, 0, dst_x,
                   dst_y - (p_btnPlay->height >> 1),
784
                   p_btnPlay->width, p_btnPlay->height );
785
        dst_x += BTN_SPACE + p_btnPlay->width;
786 787 788
    }

    if( p_btnStop )
789 790
        XPutImage( p_display, control, gc, p_btnStop, 0, 0, dst_x,
                   dst_y - (p_btnStop->height >> 1),
791
                   p_btnStop->width, p_btnStop->height );
792 793 794

    dst_x += BTN_SPACE + ( p_btnStop ? p_btnStop->width : 0 );

795
    if( p_btnFullscreen )
796 797
        XPutImage( p_display, control, gc, p_btnFullscreen, 0, 0, dst_x,
                   dst_y - (p_btnFullscreen->height >> 1),
798 799
                   p_btnFullscreen->width, p_btnFullscreen->height );

800 801
    dst_x += BTN_SPACE + ( p_btnFullscreen ? p_btnFullscreen->width : 0 );

802 803
    if( p_btnUnmute && b_mute )
    {
804 805
        XPutImage( p_display, control, gc, p_btnUnmute, 0, 0, dst_x,
                   dst_y - (p_btnUnmute->height >> 1),
806
                   p_btnUnmute->width, p_btnUnmute->height );
807 808

        dst_x += BTN_SPACE + ( p_btnUnmute ? p_btnUnmute->width : 0 );
809 810 811
    }
    else if( p_btnMute )
    {
812 813
        XPutImage( p_display, control, gc, p_btnMute, 0, 0, dst_x,
                   dst_y - (p_btnMute->height >> 1),
814
                   p_btnMute->width, p_btnMute->height );
815 816

        dst_x += BTN_SPACE + ( p_btnMute ? p_btnMute->width : 0 );
817 818 819
    }

    if( p_timeline )
820 821
        XPutImage( p_display, control, gc, p_timeline, 0, 0, dst_x,
                   dst_y - (p_timeline->height >> 1),
822
                   (window.width-(dst_x+BTN_SPACE)), p_timeline->height );
823

824 825 826 827 828 829 830
    /* get movie position in % */
    if( playlist_isplaying(&ex) )
    {
        i_last_position = (int)((window.width-(dst_x+BTN_SPACE))*
                   libvlc_media_player_get_position(libvlc_media_player,&ex));
    }
    libvlc_exception_clear( &ex );
831

832 833
    if( p_btnTime )
        XPutImage( p_display, control, gc, p_btnTime,
834 835
                   0, 0, (dst_x+i_last_position),
                   dst_y - (p_btnTime->height >> 1),
836 837 838 839
                   p_btnTime->width, p_btnTime->height );

    XFreeGC( p_display, gc );
}
840 841 842

vlc_toolbar_clicked_t VlcPlugin::getToolbarButtonClicked( int i_xpos, int i_ypos )
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
843
    unsigned int i_dest = BTN_SPACE;
844
    int is_playing = 0;
845 846 847
    bool b_mute = false;
    libvlc_exception_t ex;

Jean-Paul Saman's avatar
Jean-Paul Saman committed
848
#ifndef NDEBUG
849 850 851
    fprintf( stderr, "ToolbarButtonClicked:: "
                     "trying to match (%d,%d) (%d,%d)\n",
             i_xpos, i_ypos, i_tb_height, i_tb_width );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
852
#endif
853
    if( i_ypos >= i_tb_width )
854 855 856 857 858 859 860 861 862
        return clicked_Unknown;

    /* Note: the order of testing is dependend on the original
     * drawing positions of the icon buttons. Buttons are tested
     * left to right.
     */

    /* get isplaying */
    libvlc_exception_init( &ex );
863
    is_playing = playlist_isplaying( &ex );
864 865 866 867 868 869 870
    libvlc_exception_clear( &ex );

    /* get mute info */
    b_mute = libvlc_audio_get_mute( getVLC(), &ex );
    libvlc_exception_clear( &ex );

    /* is Pause of Play button clicked */
871
    if( (is_playing != 1) &&
872 873
        (i_xpos >= (BTN_SPACE>>1)) &&
        (i_xpos <= i_dest + p_btnPlay->width + (BTN_SPACE>>1)) )
874
        return clicked_Play;
875 876
    else if( (i_xpos >= (BTN_SPACE>>1))  &&
             (i_xpos <= i_dest + p_btnPause->width) )
877 878 879
        return clicked_Pause;

    /* is Stop button clicked */
880
    if( is_playing != 1 )
881
        i_dest += (p_btnPlay->width + (BTN_SPACE>>1));
882
    else
883 884 885 886
        i_dest += (p_btnPause->width + (BTN_SPACE>>1));

    if( (i_xpos >= i_dest) &&
        (i_xpos <= i_dest + p_btnStop->width + (BTN_SPACE>>1)) )
887 888 889 890
        return clicked_Stop;

    /* is Fullscreen button clicked */
    i_dest += (p_btnStop->width + (BTN_SPACE>>1));
891 892
    if( (i_xpos >= i_dest) &&
        (i_xpos <= i_dest + p_btnFullscreen->width + (BTN_SPACE>>1)) )
893 894 895 896
        return clicked_Fullscreen;

    /* is Mute or Unmute button clicked */
    i_dest += (p_btnFullscreen->width + (BTN_SPACE>>1));
897 898
    if( !b_mute && (i_xpos >= i_dest) &&
        (i_xpos <= i_dest + p_btnMute->width + (BTN_SPACE>>1)) )
899
        return clicked_Mute;
900 901
    else if( (i_xpos >= i_dest) &&
             (i_xpos <= i_dest + p_btnUnmute->width + (BTN_SPACE>>1)) )
902 903 904 905 906 907 908
        return clicked_Unmute;

    /* is timeline clicked */
    if( !b_mute )
        i_dest += (p_btnMute->width + (BTN_SPACE>>1));
    else
        i_dest += (p_btnUnmute->width + (BTN_SPACE>>1));
909 910
    if( (i_xpos >= i_dest) &&
        (i_xpos <= i_dest + p_timeline->width + (BTN_SPACE>>1)) )
911 912 913 914
        return clicked_timeline;

    /* is time button clicked */
    i_dest += (p_timeline->width + (BTN_SPACE>>1));
915 916
    if( (i_xpos >= i_dest) &&
        (i_xpos <= i_dest + p_btnTime->width + (BTN_SPACE>>1)) )
917 918 919 920 921
        return clicked_Time;

    return clicked_Unknown;
}
#undef BTN_SPACE
922
#endif