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