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