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