]> git.sesse.net Git - vlc/blob - projects/mozilla/vlcplugin.cpp
Mozilla plugin event listeners.
[vlc] / projects / mozilla / vlcplugin.cpp
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  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "config.h"
30
31 #ifdef HAVE_MOZILLA_CONFIG_H
32 #   include <mozilla-config.h>
33 #endif
34
35 #include "vlcplugin.h"
36 #include "control/npolibvlc.h"
37
38 #include <ctype.h>
39 #include <string>
40
41 /*****************************************************************************
42  * VlcPlugin constructor and destructor
43  *****************************************************************************/
44 VlcPlugin::VlcPlugin( NPP instance, uint16 mode ) :
45     i_npmode(mode),
46     b_stream(0),
47     b_autoplay(1),
48     b_toolbar(0),
49     psz_text(NULL),
50     psz_target(NULL),
51     playlist_index(-1),
52     libvlc_instance(NULL),
53     libvlc_media_list(NULL),
54     libvlc_media_player(NULL),
55     p_scriptClass(NULL),
56     p_browser(instance),
57     psz_baseURL(NULL)
58 #if defined(XP_WIN)
59     ,pf_wndproc(NULL)
60 #endif
61 #if defined(XP_UNIX)
62     ,i_width((unsigned)-1)
63     ,i_height((unsigned)-1)
64     ,i_tb_width(0)
65     ,i_tb_height(0)
66     ,i_last_position(0)
67     ,p_btnPlay(NULL)
68     ,p_btnPause(NULL)
69     ,p_btnStop(NULL)
70     ,p_btnMute(NULL)
71     ,p_btnUnmute(NULL)
72     ,p_btnFullscreen(NULL)
73     ,p_btnTime(NULL)
74     ,p_timeline(NULL)
75 #endif
76 {
77     memset(&npwindow, 0, sizeof(NPWindow));
78 #if defined(XP_UNIX)
79     memset(&npvideo, 0, sizeof(Window));
80     memset(&npcontrol, 0, sizeof(Window));
81 #endif
82 }
83
84 static bool boolValue(const char *value) {
85     return ( !strcmp(value, "1") ||
86              !strcasecmp(value, "true") ||
87              !strcasecmp(value, "yes") );
88 }
89
90 void eventAsync(void *param)
91 {
92     VlcPlugin *plugin = (VlcPlugin*)param;
93     NPVariant result;
94     NPVariant params[2];
95
96     pthread_mutex_lock(&plugin->mutex);
97
98     for (int i = 0; i < plugin->eventList.size(); i++)
99     {
100         for (int j = 0; j < plugin->eventListeners.size(); j++)
101         {
102             libvlc_event_type_t event = plugin->eventList[i];
103
104             if (plugin->eventListeners[j]->eventMap.have_event(event))
105             {
106                 STRINGZ_TO_NPVARIANT(libvlc_event_type_name(event), params[0]);
107                 params[1] = plugin->eventListeners[j]->id;
108                 NPN_InvokeDefault(plugin->getBrowser(), plugin->eventListeners[j]->listener, params, 2, &result);
109                 NPN_ReleaseVariantValue(&result);
110             }
111         }
112     }
113     plugin->eventList.clear();
114
115     pthread_mutex_unlock(&plugin->mutex);
116 }
117
118 void event_callback(const libvlc_event_t* event, void *param)
119 {
120     VlcPlugin *plugin = (VlcPlugin*)param;
121
122     pthread_mutex_lock(&plugin->mutex);
123
124     if (plugin->eventToCatch.have_event(event->type))
125         plugin->eventList.push_back(event->type);
126
127     pthread_mutex_unlock(&plugin->mutex);
128
129     NPN_PluginThreadAsyncCall(plugin->getBrowser(), eventAsync, plugin);
130 }
131
132 NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
133 {
134     /* prepare VLC command line */
135     const char *ppsz_argv[32];
136     int ppsz_argc = 0;
137
138 #ifndef NDEBUG
139     ppsz_argv[ppsz_argc++] = "--no-plugins-cache";
140 #endif
141
142     /* locate VLC module path */
143 #ifdef XP_MACOSX
144     ppsz_argv[ppsz_argc++] = "--plugin-path=/Library/Internet\\ Plug-Ins/VLC\\ Plugin.plugin/Contents/MacOS/modules";
145     ppsz_argv[ppsz_argc++] = "--vout=minimal_macosx";
146 #elif defined(XP_WIN)
147     HKEY h_key;
148     DWORD i_type, i_data = MAX_PATH + 1;
149     char p_data[MAX_PATH + 1];
150     if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
151                       0, KEY_READ, &h_key ) == ERROR_SUCCESS )
152     {
153          if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
154                               (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
155          {
156              if( i_type == REG_SZ )
157              {
158                  strcat( p_data, "\\plugins" );
159                  ppsz_argv[ppsz_argc++] = "--plugin-path";
160                  ppsz_argv[ppsz_argc++] = p_data;
161              }
162          }
163          RegCloseKey( h_key );
164     }
165     ppsz_argv[ppsz_argc++] = "--no-one-instance";
166
167 #endif /* XP_MACOSX */
168
169     /* common settings */
170     ppsz_argv[ppsz_argc++] = "-vv";
171     ppsz_argv[ppsz_argc++] = "--no-stats";
172     ppsz_argv[ppsz_argc++] = "--no-media-library";
173     ppsz_argv[ppsz_argc++] = "--intf=dummy";
174     ppsz_argv[ppsz_argc++] = "--no-video-title-show";
175
176     const char *progid = NULL;
177
178     /* parse plugin arguments */
179     for( int i = 0; (i < argc) && (ppsz_argc < 32); i++ )
180     {
181        /* fprintf(stderr, "argn=%s, argv=%s\n", argn[i], argv[i]); */
182
183         if( !strcmp( argn[i], "target" )
184          || !strcmp( argn[i], "mrl")
185          || !strcmp( argn[i], "filename")
186          || !strcmp( argn[i], "src") )
187         {
188             psz_target = argv[i];
189         }
190         else if( !strcmp( argn[i], "text" ) )
191         {
192             free( psz_text );
193             psz_text = strdup( argv[i] );
194         }
195         else if( !strcmp( argn[i], "autoplay")
196               || !strcmp( argn[i], "autostart") )
197         {
198             b_autoplay = boolValue(argv[i]);
199         }
200         else if( !strcmp( argn[i], "fullscreen" ) )
201         {
202             if( boolValue(argv[i]) )
203             {
204                 ppsz_argv[ppsz_argc++] = "--fullscreen";
205             }
206             else
207             {
208                 ppsz_argv[ppsz_argc++] = "--no-fullscreen";
209             }
210         }
211         else if( !strcmp( argn[i], "mute" ) )
212         {
213             if( boolValue(argv[i]) )
214             {
215                 ppsz_argv[ppsz_argc++] = "--volume=0";
216             }
217         }
218         else if( !strcmp( argn[i], "loop")
219               || !strcmp( argn[i], "autoloop") )
220         {
221             if( boolValue(argv[i]) )
222             {
223                 ppsz_argv[ppsz_argc++] = "--loop";
224             }
225             else
226             {
227                 ppsz_argv[ppsz_argc++] = "--no-loop";
228             }
229         }
230         else if( !strcmp( argn[i], "version")
231               || !strcmp( argn[i], "progid") )
232         {
233             progid = argv[i];
234         }
235         else if( !strcmp( argn[i], "toolbar" ) )
236         {
237 /* FIXME: Remove this when toolbar functionality has been implemented on
238  * MacOS X and Win32 for Firefox/Mozilla/Safari. */
239 #ifdef XP_UNIX
240             b_toolbar = boolValue(argv[i]);
241 #endif
242         }
243     }
244
245     libvlc_exception_t ex;
246     libvlc_exception_init(&ex);
247
248     libvlc_instance = libvlc_new(ppsz_argc, ppsz_argv, &ex);
249     if( libvlc_exception_raised(&ex) )
250     {
251         libvlc_exception_clear(&ex);
252         return NPERR_GENERIC_ERROR;
253     }
254
255     libvlc_media_list = libvlc_media_list_new(libvlc_instance);
256
257     /*
258     ** fetch plugin base URL, which is the URL of the page containing the plugin
259     ** this URL is used for making absolute URL from relative URL that may be
260     ** passed as an MRL argument
261     */
262     NPObject *plugin = NULL;
263
264     if( NPERR_NO_ERROR == NPN_GetValue(p_browser, NPNVWindowNPObject, &plugin) )
265     {
266         /*
267         ** is there a better way to get that info ?
268         */
269         static const char docLocHref[] = "document.location.href";
270         NPString script;
271         NPVariant result;
272
273         script.utf8characters = docLocHref;
274         script.utf8length = sizeof(docLocHref)-1;
275
276         if( NPN_Evaluate(p_browser, plugin, &script, &result) )
277         {
278             if( NPVARIANT_IS_STRING(result) )
279             {
280                 NPString &location = NPVARIANT_TO_STRING(result);
281
282                 psz_baseURL = (char *) malloc(location.utf8length+1);
283                 if( psz_baseURL )
284                 {
285                     strncpy(psz_baseURL, location.utf8characters, location.utf8length);
286                     psz_baseURL[location.utf8length] = '\0';
287                 }
288             }
289             NPN_ReleaseVariantValue(&result);
290         }
291         NPN_ReleaseObject(plugin);
292     }
293
294     if( psz_target )
295     {
296         // get absolute URL from src
297         char *psz_absurl = getAbsoluteURL(psz_target);
298         psz_target = psz_absurl ? psz_absurl : strdup(psz_target);
299     }
300
301     /* assign plugin script root class */
302     /* new APIs */
303     p_scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
304
305     if (pthread_mutex_init(&mutex, NULL) != 0)
306         return NPERR_GENERIC_ERROR;
307
308     return NPERR_NO_ERROR;
309 }
310
311 VlcPlugin::~VlcPlugin()
312 {
313     free(psz_baseURL);
314     free(psz_target);
315     free(psz_text);
316
317     if( libvlc_media_player )
318         libvlc_media_player_release( libvlc_media_player );
319     if( libvlc_media_list )
320         libvlc_media_list_release( libvlc_media_list );
321     if( libvlc_instance )
322         libvlc_release(libvlc_instance);
323     
324     for (int i = 0; i < eventListeners.size(); i++)
325     {
326         NPN_ReleaseObject(eventListeners[i]->listener);
327         NPN_ReleaseVariantValue(&(eventListeners[i]->id));
328         delete eventListeners[i];
329     }
330
331     pthread_mutex_destroy(&mutex);
332 }
333
334 /*****************************************************************************
335  * VlcPlugin playlist replacement methods
336  *****************************************************************************/
337 void VlcPlugin::set_player_window()
338 {
339 #ifdef XP_UNIX
340     libvlc_media_player_set_xwindow(libvlc_media_player,
341                                     (libvlc_drawable_t)getVideoWindow());
342 #endif
343 #ifdef XP_MACOSX
344     // XXX FIXME insert appropriate call here
345 #endif
346 #ifdef XP_WIN
347     libvlc_media_player_set_hwnd(libvlc_media_player,
348                                  getWindow().window);
349 #endif
350 }
351
352 int VlcPlugin::playlist_add( const char *mrl, libvlc_exception_t *ex )
353 {
354     int item = -1;
355     libvlc_media_t *p_m = libvlc_media_new(libvlc_instance,mrl,ex);
356     if( libvlc_exception_raised(ex) )
357         return -1;
358
359     libvlc_media_list_lock(libvlc_media_list);
360     libvlc_media_list_add_media(libvlc_media_list,p_m,ex);
361     if( !libvlc_exception_raised(ex) )
362         item = libvlc_media_list_count(libvlc_media_list)-1;
363     libvlc_media_list_unlock(libvlc_media_list);
364
365     libvlc_media_release(p_m);
366
367     return item;
368 }
369
370 int VlcPlugin::playlist_add_extended_untrusted( const char *mrl, const char *name,
371                     int optc, const char **optv, libvlc_exception_t *ex )
372 {
373     libvlc_media_t *p_m = libvlc_media_new(libvlc_instance, mrl,ex);
374     int item = -1;
375     if( libvlc_exception_raised(ex) )
376         return -1;
377
378     for( int i = 0; i < optc; ++i )
379         libvlc_media_add_option_flag(p_m, optv[i], libvlc_media_option_unique);
380
381     libvlc_media_list_lock(libvlc_media_list);
382     libvlc_media_list_add_media(libvlc_media_list,p_m,ex);
383     if( !libvlc_exception_raised(ex) )
384         item = libvlc_media_list_count(libvlc_media_list)-1;
385     libvlc_media_list_unlock(libvlc_media_list);
386     libvlc_media_release(p_m);
387
388     return item;
389 }
390
391 bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
392 {
393     libvlc_media_t *p_m = NULL;
394     libvlc_event_manager_t *eventManager = NULL;
395
396     libvlc_media_list_lock(libvlc_media_list);
397
398     int count = libvlc_media_list_count(libvlc_media_list);
399
400     if( idx<0||idx>=count )
401         goto bad_unlock;
402
403     playlist_index = idx;
404
405     p_m = libvlc_media_list_item_at_index(libvlc_media_list,playlist_index,ex);
406     libvlc_media_list_unlock(libvlc_media_list);
407
408     if( libvlc_exception_raised(ex) )
409         return false;
410
411     if( libvlc_media_player )
412     {
413         libvlc_media_player_release( libvlc_media_player );
414         libvlc_media_player = NULL;
415     }
416
417     libvlc_media_player = libvlc_media_player_new_from_media(p_m,ex);
418     if( libvlc_media_player )
419     {
420         set_player_window();
421
422         // Registers the events we're interested in.
423         eventManager = libvlc_media_player_event_manager(libvlc_media_player, ex);
424
425         libvlc_event_attach(eventManager, libvlc_MediaPlayerOpening, event_callback, this, ex);
426         libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, event_callback, this, ex);
427         libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, event_callback, this, ex);
428         libvlc_event_attach(eventManager, libvlc_MediaPlayerStopped, event_callback, this, ex);
429         libvlc_event_attach(eventManager, libvlc_MediaPlayerPaused, event_callback, this, ex);
430         libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex);
431         libvlc_event_attach(eventManager, libvlc_MediaPlayerForward, event_callback, this, ex);
432         libvlc_event_attach(eventManager, libvlc_MediaPlayerBackward, event_callback, this, ex);
433         libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex);
434         libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, event_callback, this, ex);
435         libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged, event_callback, this, ex);
436         libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, event_callback, this, ex);
437         libvlc_event_attach(eventManager, libvlc_MediaPlayerTitleChanged, event_callback, this, ex);
438         libvlc_event_attach(eventManager, libvlc_MediaPlayerSnapshotTaken, event_callback, this, ex);
439
440     }
441
442     libvlc_media_release( p_m );
443     return !libvlc_exception_raised(ex);
444
445 bad_unlock:
446     libvlc_media_list_unlock(libvlc_media_list);
447     return false;
448 }
449
450 void VlcPlugin::playlist_delete_item( int idx, libvlc_exception_t *ex )
451 {
452     libvlc_media_list_lock(libvlc_media_list);
453     libvlc_media_list_remove_index(libvlc_media_list,idx,ex);
454     libvlc_media_list_unlock(libvlc_media_list);
455 }
456
457 void VlcPlugin::playlist_clear( libvlc_exception_t *ex )
458 {
459     if( libvlc_media_list )
460         libvlc_media_list_release(libvlc_media_list);
461     libvlc_media_list = libvlc_media_list_new(getVLC());
462 }
463
464 int VlcPlugin::playlist_count()
465 {
466     int items_count = 0;
467     libvlc_media_list_lock(libvlc_media_list);
468     items_count = libvlc_media_list_count(libvlc_media_list);
469     libvlc_media_list_unlock(libvlc_media_list);
470     return items_count;
471 }
472
473 void VlcPlugin::toggle_fullscreen( libvlc_exception_t *ex )
474 {
475     if( playlist_isplaying() )
476         libvlc_toggle_fullscreen(libvlc_media_player,ex);
477 }
478 void VlcPlugin::set_fullscreen( int yes, libvlc_exception_t *ex )
479 {
480     if( playlist_isplaying() )
481         libvlc_set_fullscreen(libvlc_media_player,yes,ex);
482 }
483 int  VlcPlugin::get_fullscreen( libvlc_exception_t *ex )
484 {
485     int r = 0;
486     if( playlist_isplaying() )
487         r = libvlc_get_fullscreen(libvlc_media_player,ex);
488     return r;
489 }
490
491 bool  VlcPlugin::player_has_vout( libvlc_exception_t *ex )
492 {
493     bool r = false;
494     if( playlist_isplaying() )
495         r = libvlc_media_player_has_vout(libvlc_media_player, ex);
496     return r;
497 }
498
499 /*****************************************************************************
500  * VlcPlugin methods
501  *****************************************************************************/
502
503 char *VlcPlugin::getAbsoluteURL(const char *url)
504 {
505     if( NULL != url )
506     {
507         // check whether URL is already absolute
508         const char *end=strchr(url, ':');
509         if( (NULL != end) && (end != url) )
510         {
511             // validate protocol header
512             const char *start = url;
513             char c = *start;
514             if( isalpha(c) )
515             {
516                 ++start;
517                 while( start != end )
518                 {
519                     c  = *start;
520                     if( ! (isalnum(c)
521                        || ('-' == c)
522                        || ('+' == c)
523                        || ('.' == c)
524                        || ('/' == c)) ) /* VLC uses / to allow user to specify a demuxer */
525                         // not valid protocol header, assume relative URL
526                         goto relativeurl;
527                     ++start;
528                 }
529                 /* we have a protocol header, therefore URL is absolute */
530                 return strdup(url);
531             }
532             // not a valid protocol header, assume relative URL
533         }
534
535 relativeurl:
536
537         if( psz_baseURL )
538         {
539             size_t baseLen = strlen(psz_baseURL);
540             char *href = (char *) malloc(baseLen+strlen(url)+1);
541             if( href )
542             {
543                 /* prepend base URL */
544                 memcpy(href, psz_baseURL, baseLen+1);
545
546                 /*
547                 ** relative url could be empty,
548                 ** in which case return base URL
549                 */
550                 if( '\0' == *url )
551                     return href;
552
553                 /*
554                 ** locate pathname part of base URL
555                 */
556
557                 /* skip over protocol part  */
558                 char *pathstart = strchr(href, ':');
559                 char *pathend = href+baseLen;
560                 if( pathstart )
561                 {
562                     if( '/' == *(++pathstart) )
563                     {
564                         if( '/' == *(++pathstart) )
565                         {
566                             ++pathstart;
567                         }
568                     }
569                     /* skip over host part */
570                     pathstart = strchr(pathstart, '/');
571                     if( ! pathstart )
572                     {
573                         // no path, add a / past end of url (over '\0')
574                         pathstart = pathend;
575                         *pathstart = '/';
576                     }
577                 }
578                 else
579                 {
580                     /* baseURL is just a UNIX path */
581                     if( '/' != *href )
582                     {
583                         /* baseURL is not an absolute path */
584                         free(href);
585                         return NULL;
586                     }
587                     pathstart = href;
588                 }
589
590                 /* relative URL made of an absolute path ? */
591                 if( '/' == *url )
592                 {
593                     /* replace path completely */
594                     strcpy(pathstart, url);
595                     return href;
596                 }
597
598                 /* find last path component and replace it */
599                 while( '/' != *pathend)
600                     --pathend;
601
602                 /*
603                 ** if relative url path starts with one or more '../',
604                 ** factor them out of href so that we return a
605                 ** normalized URL
606                 */
607                 while( pathend != pathstart )
608                 {
609                     const char *p = url;
610                     if( '.' != *p )
611                         break;
612                     ++p;
613                     if( '\0' == *p  )
614                     {
615                         /* relative url is just '.' */
616                         url = p;
617                         break;
618                     }
619                     if( '/' == *p  )
620                     {
621                         /* relative url starts with './' */
622                         url = ++p;
623                         continue;
624                     }
625                     if( '.' != *p )
626                         break;
627                     ++p;
628                     if( '\0' == *p )
629                     {
630                         /* relative url is '..' */
631                     }
632                     else
633                     {
634                         if( '/' != *p )
635                             break;
636                         /* relative url starts with '../' */
637                         ++p;
638                     }
639                     url = p;
640                     do
641                     {
642                         --pathend;
643                     }
644                     while( '/' != *pathend );
645                 }
646                 /* skip over '/' separator */
647                 ++pathend;
648                 /* concatenate remaining base URL and relative URL */
649                 strcpy(pathend, url);
650             }
651             return href;
652         }
653     }
654     return NULL;
655 }
656
657 #if defined(XP_UNIX)
658 int  VlcPlugin::setSize(unsigned width, unsigned height)
659 {
660     int diff = (width != i_width) || (height != i_height);
661
662     i_width = width;
663     i_height = height;
664
665     /* return size */
666     return diff;
667 }
668
669 #define BTN_SPACE ((unsigned int)4)
670 void VlcPlugin::showToolbar()
671 {
672     const NPWindow& window = getWindow();
673     Window control = getControlWindow();
674     Window video = getVideoWindow();
675     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
676     unsigned int i_height = 0, i_width = BTN_SPACE;
677
678     /* load icons */
679     if( !p_btnPlay )
680         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/play.xpm",
681                             &p_btnPlay, NULL, NULL);
682     if( p_btnPlay )
683     {
684         i_height = __MAX( i_height, p_btnPlay->height );
685     }
686     if( !p_btnPause )
687         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/pause.xpm",
688                             &p_btnPause, NULL, NULL);
689     if( p_btnPause )
690     {
691         i_height = __MAX( i_height, p_btnPause->height );
692     }
693     i_width += __MAX( p_btnPause->width, p_btnPlay->width );
694
695     if( !p_btnStop )
696         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/stop.xpm",
697                             &p_btnStop, NULL, NULL );
698     if( p_btnStop )
699     {
700         i_height = __MAX( i_height, p_btnStop->height );
701         i_width += BTN_SPACE + p_btnStop->width;
702     }
703     if( !p_timeline )
704         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/time_line.xpm",
705                             &p_timeline, NULL, NULL);
706     if( p_timeline )
707     {
708         i_height = __MAX( i_height, p_timeline->height );
709         i_width += BTN_SPACE + p_timeline->width;
710     }
711     if( !p_btnTime )
712         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/time_icon.xpm",
713                             &p_btnTime, NULL, NULL);
714     if( p_btnTime )
715     {
716         i_height = __MAX( i_height, p_btnTime->height );
717         i_width += BTN_SPACE + p_btnTime->width;
718     }
719     if( !p_btnFullscreen )
720         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/fullscreen.xpm",
721                             &p_btnFullscreen, NULL, NULL);
722     if( p_btnFullscreen )
723     {
724         i_height = __MAX( i_height, p_btnFullscreen->height );
725         i_width += BTN_SPACE + p_btnFullscreen->width;
726     }
727     if( !p_btnMute )
728         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/volume_max.xpm",
729                             &p_btnMute, NULL, NULL);
730     if( p_btnMute )
731     {
732         i_height = __MAX( i_height, p_btnMute->height );
733     }
734     if( !p_btnUnmute )
735         XpmReadFileToImage( p_display, DATA_PATH "/mozilla/volume_mute.xpm",
736                             &p_btnUnmute, NULL, NULL);
737     if( p_btnUnmute )
738     {
739         i_height = __MAX( i_height, p_btnUnmute->height );
740     }
741     i_width += BTN_SPACE + __MAX( p_btnUnmute->width, p_btnMute->width );
742
743     setToolbarSize( i_width, i_height );
744
745     if( !p_btnPlay || !p_btnPause || !p_btnStop || !p_timeline ||
746         !p_btnTime || !p_btnFullscreen || !p_btnMute || !p_btnUnmute )
747         fprintf(stderr, "Error: some button images not found in %s\n", DATA_PATH );
748
749     /* reset panels position and size */
750     /* XXX  use i_width */
751     XResizeWindow( p_display, video, window.width, window.height - i_height);
752     XMoveWindow( p_display, control, 0, window.height - i_height );
753     XResizeWindow( p_display, control, window.width, i_height -1);
754
755     b_toolbar = 1; /* says toolbar is now shown */
756     redrawToolbar();
757 }
758
759 void VlcPlugin::hideToolbar()
760 {
761     const NPWindow& window = getWindow();
762     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
763     Window control = getControlWindow();
764     Window video = getVideoWindow();
765
766     i_tb_width = i_tb_height = 0;
767
768     if( p_btnPlay )  XDestroyImage( p_btnPlay );
769     if( p_btnPause ) XDestroyImage( p_btnPause );
770     if( p_btnStop )  XDestroyImage( p_btnStop );
771     if( p_timeline ) XDestroyImage( p_timeline );
772     if( p_btnTime )  XDestroyImage( p_btnTime );
773     if( p_btnFullscreen ) XDestroyImage( p_btnFullscreen );
774     if( p_btnMute )  XDestroyImage( p_btnMute );
775     if( p_btnUnmute ) XDestroyImage( p_btnUnmute );
776
777     p_btnPlay = NULL;
778     p_btnPause = NULL;
779     p_btnStop = NULL;
780     p_timeline = NULL;
781     p_btnTime = NULL;
782     p_btnFullscreen = NULL;
783     p_btnMute = NULL;
784     p_btnUnmute = NULL;
785
786     /* reset panels position and size */
787     /* XXX  use i_width */
788     XResizeWindow( p_display, video, window.width, window.height );
789     XMoveWindow( p_display, control, 0, window.height-1 );
790     XResizeWindow( p_display, control, window.width, 1 );
791
792     b_toolbar = 0; /* says toolbar is now hidden */
793     redrawToolbar();
794 }
795
796 void VlcPlugin::redrawToolbar()
797 {
798     int is_playing = 0;
799     bool b_mute = false;
800     unsigned int dst_x, dst_y;
801     GC gc;
802     XGCValues gcv;
803     unsigned int i_tb_width, i_tb_height;
804
805     /* This method does nothing if toolbar is hidden. */
806     if( !b_toolbar )
807         return;
808
809     const NPWindow& window = getWindow();
810     Window control = getControlWindow();
811     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
812
813     getToolbarSize( &i_tb_width, &i_tb_height );
814
815
816     /* get mute info */
817     b_mute = libvlc_audio_get_mute( getVLC() );
818
819     gcv.foreground = BlackPixel( p_display, 0 );
820     gc = XCreateGC( p_display, control, GCForeground, &gcv );
821
822     XFillRectangle( p_display, control, gc,
823                     0, 0, window.width, i_tb_height );
824     gcv.foreground = WhitePixel( p_display, 0 );
825     XChangeGC( p_display, gc, GCForeground, &gcv );
826
827     /* position icons */
828     dst_x = BTN_SPACE;
829     dst_y = i_tb_height >> 1; /* baseline = vertical middle */
830
831     if( p_btnPause && (is_playing == 1) )
832     {
833         XPutImage( p_display, control, gc, p_btnPause, 0, 0, dst_x,
834                    dst_y - (p_btnPause->height >> 1),
835                    p_btnPause->width, p_btnPause->height );
836         dst_x += BTN_SPACE + p_btnPause->width;
837     }
838     else if( p_btnPlay )
839     {
840         XPutImage( p_display, control, gc, p_btnPlay, 0, 0, dst_x,
841                    dst_y - (p_btnPlay->height >> 1),
842                    p_btnPlay->width, p_btnPlay->height );
843         dst_x += BTN_SPACE + p_btnPlay->width;
844     }
845
846     if( p_btnStop )
847         XPutImage( p_display, control, gc, p_btnStop, 0, 0, dst_x,
848                    dst_y - (p_btnStop->height >> 1),
849                    p_btnStop->width, p_btnStop->height );
850
851     dst_x += BTN_SPACE + ( p_btnStop ? p_btnStop->width : 0 );
852
853     if( p_btnFullscreen )
854         XPutImage( p_display, control, gc, p_btnFullscreen, 0, 0, dst_x,
855                    dst_y - (p_btnFullscreen->height >> 1),
856                    p_btnFullscreen->width, p_btnFullscreen->height );
857
858     dst_x += BTN_SPACE + ( p_btnFullscreen ? p_btnFullscreen->width : 0 );
859
860     if( p_btnUnmute && b_mute )
861     {
862         XPutImage( p_display, control, gc, p_btnUnmute, 0, 0, dst_x,
863                    dst_y - (p_btnUnmute->height >> 1),
864                    p_btnUnmute->width, p_btnUnmute->height );
865
866         dst_x += BTN_SPACE + ( p_btnUnmute ? p_btnUnmute->width : 0 );
867     }
868     else if( p_btnMute )
869     {
870         XPutImage( p_display, control, gc, p_btnMute, 0, 0, dst_x,
871                    dst_y - (p_btnMute->height >> 1),
872                    p_btnMute->width, p_btnMute->height );
873
874         dst_x += BTN_SPACE + ( p_btnMute ? p_btnMute->width : 0 );
875     }
876
877     if( p_timeline )
878         XPutImage( p_display, control, gc, p_timeline, 0, 0, dst_x,
879                    dst_y - (p_timeline->height >> 1),
880                    (window.width-(dst_x+BTN_SPACE)), p_timeline->height );
881
882     /* get movie position in % */
883     if( playlist_isplaying() )
884     {
885         libvlc_exception_t ex;
886         libvlc_exception_init( &ex );
887         i_last_position = (int)((window.width-(dst_x+BTN_SPACE))*
888                    libvlc_media_player_get_position(libvlc_media_player,&ex));
889         libvlc_exception_clear( &ex );
890     }
891
892     if( p_btnTime )
893         XPutImage( p_display, control, gc, p_btnTime,
894                    0, 0, (dst_x+i_last_position),
895                    dst_y - (p_btnTime->height >> 1),
896                    p_btnTime->width, p_btnTime->height );
897
898     XFreeGC( p_display, gc );
899 }
900
901 vlc_toolbar_clicked_t VlcPlugin::getToolbarButtonClicked( int i_xpos, int i_ypos )
902 {
903     unsigned int i_dest = BTN_SPACE;
904     int is_playing = 0;
905     bool b_mute = false;
906
907 #ifndef NDEBUG
908     fprintf( stderr, "ToolbarButtonClicked:: "
909                      "trying to match (%d,%d) (%d,%d)\n",
910              i_xpos, i_ypos, i_tb_height, i_tb_width );
911 #endif
912     if( i_ypos >= i_tb_width )
913         return clicked_Unknown;
914
915     /* Note: the order of testing is dependend on the original
916      * drawing positions of the icon buttons. Buttons are tested
917      * left to right.
918      */
919
920     /* get isplaying */
921     is_playing = playlist_isplaying();
922
923     /* get mute info */
924     b_mute = libvlc_audio_get_mute( getVLC() );
925
926     /* is Pause of Play button clicked */
927     if( (is_playing != 1) &&
928         (i_xpos >= (BTN_SPACE>>1)) &&
929         (i_xpos <= i_dest + p_btnPlay->width + (BTN_SPACE>>1)) )
930         return clicked_Play;
931     else if( (i_xpos >= (BTN_SPACE>>1))  &&
932              (i_xpos <= i_dest + p_btnPause->width) )
933         return clicked_Pause;
934
935     /* is Stop button clicked */
936     if( is_playing != 1 )
937         i_dest += (p_btnPlay->width + (BTN_SPACE>>1));
938     else
939         i_dest += (p_btnPause->width + (BTN_SPACE>>1));
940
941     if( (i_xpos >= i_dest) &&
942         (i_xpos <= i_dest + p_btnStop->width + (BTN_SPACE>>1)) )
943         return clicked_Stop;
944
945     /* is Fullscreen button clicked */
946     i_dest += (p_btnStop->width + (BTN_SPACE>>1));
947     if( (i_xpos >= i_dest) &&
948         (i_xpos <= i_dest + p_btnFullscreen->width + (BTN_SPACE>>1)) )
949         return clicked_Fullscreen;
950
951     /* is Mute or Unmute button clicked */
952     i_dest += (p_btnFullscreen->width + (BTN_SPACE>>1));
953     if( !b_mute && (i_xpos >= i_dest) &&
954         (i_xpos <= i_dest + p_btnMute->width + (BTN_SPACE>>1)) )
955         return clicked_Mute;
956     else if( (i_xpos >= i_dest) &&
957              (i_xpos <= i_dest + p_btnUnmute->width + (BTN_SPACE>>1)) )
958         return clicked_Unmute;
959
960     /* is timeline clicked */
961     if( !b_mute )
962         i_dest += (p_btnMute->width + (BTN_SPACE>>1));
963     else
964         i_dest += (p_btnUnmute->width + (BTN_SPACE>>1));
965     if( (i_xpos >= i_dest) &&
966         (i_xpos <= i_dest + p_timeline->width + (BTN_SPACE>>1)) )
967         return clicked_timeline;
968
969     /* is time button clicked */
970     i_dest += (p_timeline->width + (BTN_SPACE>>1));
971     if( (i_xpos >= i_dest) &&
972         (i_xpos <= i_dest + p_btnTime->width + (BTN_SPACE>>1)) )
973         return clicked_Time;
974
975     return clicked_Unknown;
976 }
977 #undef BTN_SPACE
978 #endif
979
980 // Verifies the version of the NPAPI.
981 // The eventListeners use a NPAPI function available
982 // since Gecko 1.9.
983 bool VlcPlugin::canUseEventListener()
984 {
985     int plugin_major, plugin_minor;
986     int browser_major, browser_minor;
987
988     NPN_Version(&plugin_major, &plugin_minor,
989                 &browser_major, &browser_minor);
990
991     if (browser_minor >= 19 || browser_major > 0)
992         return true;
993     return false;
994 }
995