1 /*****************************************************************************
2 * vlcplugin.cpp: a VLC plugin for Mozilla
3 *****************************************************************************
4 * Copyright (C) 2002-2008 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Damien Fouilleul <damienf.fouilleul@laposte.net>
9 * Jean-Paul Saman <jpsaman@videolan.org>
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
31 #ifdef HAVE_MOZILLA_CONFIG_H
32 # include <mozilla-config.h>
35 #include "vlcplugin.h"
36 #include "control/npolibvlc.h"
40 /*****************************************************************************
41 * VlcPlugin constructor and destructor
42 *****************************************************************************/
43 VlcPlugin::VlcPlugin( NPP instance
, uint16 mode
) :
49 libvlc_instance(NULL
),
58 ,i_width((unsigned)-1)
59 ,i_height((unsigned)-1)
68 ,p_btnFullscreen(NULL
)
73 memset(&npwindow
, 0, sizeof(NPWindow
));
76 static bool boolValue(const char *value
) {
77 return ( !strcmp(value
, "1") ||
78 !strcasecmp(value
, "true") ||
79 !strcasecmp(value
, "yes") );
82 NPError
VlcPlugin::init(int argc
, char* const argn
[], char* const argv
[])
84 /* prepare VLC command line */
85 const char *ppsz_argv
[32];
88 /* locate VLC module path */
90 ppsz_argv
[ppsz_argc
++] = "--plugin-path";
91 ppsz_argv
[ppsz_argc
++] = "/Library/Internet Plug-Ins/VLC Plugin.plugin/"
92 "Contents/MacOS/modules";
95 DWORD i_type
, i_data
= MAX_PATH
+ 1;
96 char p_data
[MAX_PATH
+ 1];
97 if( RegOpenKeyEx( HKEY_LOCAL_MACHINE
, "Software\\VideoLAN\\VLC",
98 0, KEY_READ
, &h_key
) == ERROR_SUCCESS
)
100 if( RegQueryValueEx( h_key
, "InstallDir", 0, &i_type
,
101 (LPBYTE
)p_data
, &i_data
) == ERROR_SUCCESS
)
103 if( i_type
== REG_SZ
)
105 strcat( p_data
, "\\plugins" );
106 ppsz_argv
[ppsz_argc
++] = "--plugin-path";
107 ppsz_argv
[ppsz_argc
++] = p_data
;
110 RegCloseKey( h_key
);
112 ppsz_argv
[ppsz_argc
++] = "--no-one-instance";
114 #endif /* XP_MACOSX */
116 /* common settings */
117 ppsz_argv
[ppsz_argc
++] = "-vv";
118 ppsz_argv
[ppsz_argc
++] = "--no-stats";
119 ppsz_argv
[ppsz_argc
++] = "--no-media-library";
120 ppsz_argv
[ppsz_argc
++] = "--ignore-config";
121 ppsz_argv
[ppsz_argc
++] = "--intf";
122 ppsz_argv
[ppsz_argc
++] = "dummy";
124 const char *progid
= NULL
;
126 /* parse plugin arguments */
127 for( int i
= 0; i
< argc
; i
++ )
129 fprintf(stderr
, "argn=%s, argv=%s\n", argn
[i
], argv
[i
]);
131 if( !strcmp( argn
[i
], "target" )
132 || !strcmp( argn
[i
], "mrl")
133 || !strcmp( argn
[i
], "filename")
134 || !strcmp( argn
[i
], "src") )
136 psz_target
= argv
[i
];
138 else if( !strcmp( argn
[i
], "autoplay")
139 || !strcmp( argn
[i
], "autostart") )
141 b_autoplay
= boolValue(argv
[i
]);
143 else if( !strcmp( argn
[i
], "fullscreen" ) )
145 if( boolValue(argv
[i
]) )
147 ppsz_argv
[ppsz_argc
++] = "--fullscreen";
151 ppsz_argv
[ppsz_argc
++] = "--no-fullscreen";
154 else if( !strcmp( argn
[i
], "mute" ) )
156 if( boolValue(argv
[i
]) )
158 ppsz_argv
[ppsz_argc
++] = "--volume";
159 ppsz_argv
[ppsz_argc
++] = "0";
162 else if( !strcmp( argn
[i
], "loop")
163 || !strcmp( argn
[i
], "autoloop") )
165 if( boolValue(argv
[i
]) )
167 ppsz_argv
[ppsz_argc
++] = "--loop";
171 ppsz_argv
[ppsz_argc
++] = "--no-loop";
174 else if( !strcmp( argn
[i
], "version")
175 || !strcmp( argn
[i
], "progid") )
179 else if( !strcmp( argn
[i
], "toolbar" ) )
181 b_toolbar
= boolValue(argv
[i
]);
185 libvlc_exception_t ex
;
186 libvlc_exception_init(&ex
);
188 libvlc_instance
= libvlc_new(ppsz_argc
, ppsz_argv
, &ex
);
189 if( libvlc_exception_raised(&ex
) )
191 libvlc_exception_clear(&ex
);
192 return NPERR_GENERIC_ERROR
;
194 libvlc_exception_clear(&ex
);
197 ** fetch plugin base URL, which is the URL of the page containing the plugin
198 ** this URL is used for making absolute URL from relative URL that may be
199 ** passed as an MRL argument
203 if( NPERR_NO_ERROR
== NPN_GetValue(p_browser
, NPNVWindowNPObject
, &plugin
) )
206 ** is there a better way to get that info ?
208 static const char docLocHref
[] = "document.location.href";
212 script
.utf8characters
= docLocHref
;
213 script
.utf8length
= sizeof(docLocHref
)-1;
215 if( NPN_Evaluate(p_browser
, plugin
, &script
, &result
) )
217 if( NPVARIANT_IS_STRING(result
) )
219 NPString
&location
= NPVARIANT_TO_STRING(result
);
221 psz_baseURL
= static_cast<char*>(malloc(location
.utf8length
+1));
224 strncpy(psz_baseURL
, location
.utf8characters
, location
.utf8length
);
225 psz_baseURL
[location
.utf8length
] = '\0';
228 NPN_ReleaseVariantValue(&result
);
230 NPN_ReleaseObject(plugin
);
235 // get absolute URL from src
236 char *psz_absurl
= getAbsoluteURL(psz_target
);
237 psz_target
= psz_absurl
? psz_absurl
: strdup(psz_target
);
240 /* assign plugin script root class */
242 p_scriptClass
= RuntimeNPClass
<LibvlcRootNPObject
>::getClass();
244 return NPERR_NO_ERROR
;
247 VlcPlugin::~VlcPlugin()
252 libvlc_log_close(libvlc_log
, NULL
);
253 if( libvlc_instance
)
254 libvlc_release(libvlc_instance
);
257 /*****************************************************************************
259 *****************************************************************************/
261 char *VlcPlugin::getAbsoluteURL(const char *url
)
265 // check whether URL is already absolute
266 const char *end
=strchr(url
, ':');
267 if( (NULL
!= end
) && (end
!= url
) )
269 // validate protocol header
270 const char *start
= url
;
275 while( start
!= end
)
282 || ('/' == c
)) ) /* VLC uses / to allow user to specify a demuxer */
283 // not valid protocol header, assume relative URL
287 /* we have a protocol header, therefore URL is absolute */
290 // not a valid protocol header, assume relative URL
297 size_t baseLen
= strlen(psz_baseURL
);
298 char *href
= static_cast<char*>(malloc(baseLen
+strlen(url
)+1));
301 /* prepend base URL */
302 strcpy(href
, psz_baseURL
);
305 ** relative url could be empty,
306 ** in which case return base URL
312 ** locate pathname part of base URL
315 /* skip over protocol part */
316 char *pathstart
= strchr(href
, ':');
320 if( '/' == *(++pathstart
) )
322 if( '/' == *(++pathstart
) )
327 /* skip over host part */
328 pathstart
= strchr(pathstart
, '/');
329 pathend
= href
+baseLen
;
332 // no path, add a / past end of url (over '\0')
339 /* baseURL is just a UNIX path */
342 /* baseURL is not an absolute path */
347 pathend
= href
+baseLen
;
350 /* relative URL made of an absolute path ? */
353 /* replace path completely */
354 strcpy(pathstart
, url
);
358 /* find last path component and replace it */
359 while( '/' != *pathend
)
363 ** if relative url path starts with one or more '../',
364 ** factor them out of href so that we return a
367 while( pathend
!= pathstart
)
375 /* relative url is just '.' */
381 /* relative url starts with './' */
390 /* relative url is '..' */
396 /* relative url starts with '../' */
404 while( '/' != *pathend
);
406 /* skip over '/' separator */
408 /* concatenate remaining base URL and relative URL */
409 strcpy(pathend
, url
);
418 int VlcPlugin::setSize(unsigned width
, unsigned height
)
420 int diff
= (width
!= i_width
) || (height
!= i_height
);
429 #define BTN_SPACE ((unsigned int)4)
430 void VlcPlugin::showToolbar()
432 const NPWindow
& window
= getWindow();
433 Window control
= getControlWindow();
434 Window video
= getVideoWindow();
435 Display
*p_display
= ((NPSetWindowCallbackStruct
*)window
.ws_info
)->display
;
436 unsigned int i_height
= 0, i_width
= BTN_SPACE
;
440 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/play.xpm",
441 &p_btnPlay
, NULL
, NULL
);
444 i_height
= __MAX( i_height
, p_btnPlay
->height
);
447 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/pause.xpm",
448 &p_btnPause
, NULL
, NULL
);
451 i_height
= __MAX( i_height
, p_btnPause
->height
);
453 i_width
+= __MAX( p_btnPause
->width
, p_btnPlay
->width
);
456 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/stop.xpm",
457 &p_btnStop
, NULL
, NULL
);
460 i_height
= __MAX( i_height
, p_btnStop
->height
);
461 i_width
+= BTN_SPACE
+ p_btnStop
->width
;
464 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/time_line.xpm",
465 &p_timeline
, NULL
, NULL
);
468 i_height
= __MAX( i_height
, p_timeline
->height
);
469 i_width
+= BTN_SPACE
+ p_timeline
->width
;
472 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/time_icon.xpm",
473 &p_btnTime
, NULL
, NULL
);
476 i_height
= __MAX( i_height
, p_btnTime
->height
);
477 i_width
+= BTN_SPACE
+ p_btnTime
->width
;
479 if( !p_btnFullscreen
)
480 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/fullscreen.xpm",
481 &p_btnFullscreen
, NULL
, NULL
);
482 if( p_btnFullscreen
)
484 i_height
= __MAX( i_height
, p_btnFullscreen
->height
);
485 i_width
+= BTN_SPACE
+ p_btnFullscreen
->width
;
488 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/volume_max.xpm",
489 &p_btnMute
, NULL
, NULL
);
492 i_height
= __MAX( i_height
, p_btnMute
->height
);
495 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/volume_mute.xpm",
496 &p_btnUnmute
, NULL
, NULL
);
499 i_height
= __MAX( i_height
, p_btnUnmute
->height
);
501 i_width
+= BTN_SPACE
+ __MAX( p_btnUnmute
->width
, p_btnMute
->width
);
503 setToolbarSize( i_width
, i_height
);
505 if( !p_btnPlay
|| !p_btnPause
|| !p_btnStop
|| !p_timeline
||
506 !p_btnTime
|| !p_btnFullscreen
|| !p_btnMute
|| !p_btnUnmute
)
507 fprintf(stderr
, "Error: some button images not found in %s\n", DATA_PATH
);
509 /* reset panels position and size */
510 /* XXX use i_width */
511 XResizeWindow( p_display
, video
, window
.width
, window
.height
- i_height
);
512 XMoveWindow( p_display
, control
, 0, window
.height
- i_height
);
513 XResizeWindow( p_display
, control
, window
.width
, i_height
-1);
515 b_toolbar
= 1; /* says toolbar is now shown */
519 void VlcPlugin::hideToolbar()
521 const NPWindow
& window
= getWindow();
522 Display
*p_display
= ((NPSetWindowCallbackStruct
*)window
.ws_info
)->display
;
523 Window control
= getControlWindow();
524 Window video
= getVideoWindow();
526 i_tb_width
= i_tb_height
= 0;
528 if( p_btnPlay
) XDestroyImage( p_btnPlay
);
529 if( p_btnPause
) XDestroyImage( p_btnPause
);
530 if( p_btnStop
) XDestroyImage( p_btnStop
);
531 if( p_timeline
) XDestroyImage( p_timeline
);
532 if( p_btnTime
) XDestroyImage( p_btnTime
);
533 if( p_btnFullscreen
) XDestroyImage( p_btnFullscreen
);
534 if( p_btnMute
) XDestroyImage( p_btnMute
);
535 if( p_btnUnmute
) XDestroyImage( p_btnUnmute
);
542 p_btnFullscreen
= NULL
;
546 /* reset panels position and size */
547 /* XXX use i_width */
548 XResizeWindow( p_display
, video
, window
.width
, window
.height
);
549 XMoveWindow( p_display
, control
, 0, window
.height
-1 );
550 XResizeWindow( p_display
, control
, window
.width
, 1 );
552 b_toolbar
= 0; /* says toolbar is now hidden */
556 void VlcPlugin::redrawToolbar()
558 libvlc_media_player_t
*p_md
= NULL
;
559 libvlc_exception_t ex
;
560 float f_position
= 0.0;
563 unsigned int dst_x
, dst_y
;
566 unsigned int i_tb_width
, i_tb_height
;
568 /* This method does nothing if toolbar is hidden. */
572 const NPWindow
& window
= getWindow();
573 Window control
= getControlWindow();
574 Display
*p_display
= ((NPSetWindowCallbackStruct
*)window
.ws_info
)->display
;
576 getToolbarSize( &i_tb_width
, &i_tb_height
);
578 /* get media instance */
579 libvlc_exception_init( &ex
);
580 p_md
= libvlc_playlist_get_media_player( getVLC(), &ex
);
581 libvlc_exception_clear( &ex
);
584 i_playing
= libvlc_playlist_isplaying( getVLC(), &ex
);
585 libvlc_exception_clear( &ex
);
588 b_mute
= libvlc_audio_get_mute( getVLC(), &ex
);
589 libvlc_exception_clear( &ex
);
591 /* get movie position in % */
594 f_position
= libvlc_media_player_get_position( p_md
, &ex
) * 100;
595 libvlc_exception_clear( &ex
);
597 libvlc_media_player_release( p_md
);
599 gcv
.foreground
= BlackPixel( p_display
, 0 );
600 gc
= XCreateGC( p_display
, control
, GCForeground
, &gcv
);
602 XFillRectangle( p_display
, control
, gc
,
603 0, 0, window
.width
, i_tb_height
);
604 gcv
.foreground
= WhitePixel( p_display
, 0 );
605 XChangeGC( p_display
, gc
, GCForeground
, &gcv
);
609 dst_y
= i_tb_height
>> 1; /* baseline = vertical middle */
611 if( p_btnPause
&& (i_playing
== 1) )
613 XPutImage( p_display
, control
, gc
, p_btnPause
, 0, 0, dst_x
,
614 dst_y
- (p_btnPause
->height
>> 1),
615 p_btnPause
->width
, p_btnPause
->height
);
616 dst_x
+= BTN_SPACE
+ p_btnPause
->width
;
620 XPutImage( p_display
, control
, gc
, p_btnPlay
, 0, 0, dst_x
,
621 dst_y
- (p_btnPlay
->height
>> 1),
622 p_btnPlay
->width
, p_btnPlay
->height
);
623 dst_x
+= BTN_SPACE
+ p_btnPlay
->width
;
627 XPutImage( p_display
, control
, gc
, p_btnStop
, 0, 0, dst_x
,
628 dst_y
- (p_btnStop
->height
>> 1),
629 p_btnStop
->width
, p_btnStop
->height
);
631 dst_x
+= BTN_SPACE
+ ( p_btnStop
? p_btnStop
->width
: 0 );
633 if( p_btnFullscreen
)
634 XPutImage( p_display
, control
, gc
, p_btnFullscreen
, 0, 0, dst_x
,
635 dst_y
- (p_btnFullscreen
->height
>> 1),
636 p_btnFullscreen
->width
, p_btnFullscreen
->height
);
638 dst_x
+= BTN_SPACE
+ ( p_btnFullscreen
? p_btnFullscreen
->width
: 0 );
640 if( p_btnUnmute
&& b_mute
)
642 XPutImage( p_display
, control
, gc
, p_btnUnmute
, 0, 0, dst_x
,
643 dst_y
- (p_btnUnmute
->height
>> 1),
644 p_btnUnmute
->width
, p_btnUnmute
->height
);
646 dst_x
+= BTN_SPACE
+ ( p_btnUnmute
? p_btnUnmute
->width
: 0 );
650 XPutImage( p_display
, control
, gc
, p_btnMute
, 0, 0, dst_x
,
651 dst_y
- (p_btnMute
->height
>> 1),
652 p_btnMute
->width
, p_btnMute
->height
);
654 dst_x
+= BTN_SPACE
+ ( p_btnMute
? p_btnMute
->width
: 0 );
658 XPutImage( p_display
, control
, gc
, p_timeline
, 0, 0, dst_x
,
659 dst_y
- (p_timeline
->height
>> 1),
660 (window
.width
-(dst_x
+BTN_SPACE
)), p_timeline
->height
);
663 i_last_position
= (int)( f_position
*
664 ( ((float)(window
.width
-(dst_x
+BTN_SPACE
))) / 100.0 ));
667 XPutImage( p_display
, control
, gc
, p_btnTime
,
668 0, 0, (dst_x
+i_last_position
),
669 dst_y
- (p_btnTime
->height
>> 1),
670 p_btnTime
->width
, p_btnTime
->height
);
672 XFreeGC( p_display
, gc
);
675 vlc_toolbar_clicked_t
VlcPlugin::getToolbarButtonClicked( int i_xpos
, int i_ypos
)
677 unsigned int i_dest
= BTN_SPACE
;//(i_tb_height >> 1);
680 libvlc_exception_t ex
;
682 fprintf( stderr
, "ToolbarButtonClicked:: "
683 "trying to match (%d,%d) (%d,%d)\n",
684 i_xpos
, i_ypos
, i_tb_height
, i_tb_width
);
686 if( i_ypos
>= i_tb_width
)
687 return clicked_Unknown
;
689 /* Note: the order of testing is dependend on the original
690 * drawing positions of the icon buttons. Buttons are tested
695 libvlc_exception_init( &ex
);
696 i_playing
= libvlc_playlist_isplaying( getVLC(), &ex
);
697 libvlc_exception_clear( &ex
);
700 b_mute
= libvlc_audio_get_mute( getVLC(), &ex
);
701 libvlc_exception_clear( &ex
);
703 /* is Pause of Play button clicked */
704 if( (i_playing
!= 1) &&
705 (i_xpos
>= (BTN_SPACE
>>1)) &&
706 (i_xpos
<= i_dest
+ p_btnPlay
->width
+ (BTN_SPACE
>>1)) )
708 else if( (i_xpos
>= (BTN_SPACE
>>1)) &&
709 (i_xpos
<= i_dest
+ p_btnPause
->width
) )
710 return clicked_Pause
;
712 /* is Stop button clicked */
714 i_dest
+= (p_btnPlay
->width
+ (BTN_SPACE
>>1));
716 i_dest
+= (p_btnPause
->width
+ (BTN_SPACE
>>1));
718 if( (i_xpos
>= i_dest
) &&
719 (i_xpos
<= i_dest
+ p_btnStop
->width
+ (BTN_SPACE
>>1)) )
722 /* is Fullscreen button clicked */
723 i_dest
+= (p_btnStop
->width
+ (BTN_SPACE
>>1));
724 if( (i_xpos
>= i_dest
) &&
725 (i_xpos
<= i_dest
+ p_btnFullscreen
->width
+ (BTN_SPACE
>>1)) )
726 return clicked_Fullscreen
;
728 /* is Mute or Unmute button clicked */
729 i_dest
+= (p_btnFullscreen
->width
+ (BTN_SPACE
>>1));
730 if( !b_mute
&& (i_xpos
>= i_dest
) &&
731 (i_xpos
<= i_dest
+ p_btnMute
->width
+ (BTN_SPACE
>>1)) )
733 else if( (i_xpos
>= i_dest
) &&
734 (i_xpos
<= i_dest
+ p_btnUnmute
->width
+ (BTN_SPACE
>>1)) )
735 return clicked_Unmute
;
737 /* is timeline clicked */
739 i_dest
+= (p_btnMute
->width
+ (BTN_SPACE
>>1));
741 i_dest
+= (p_btnUnmute
->width
+ (BTN_SPACE
>>1));
742 if( (i_xpos
>= i_dest
) &&
743 (i_xpos
<= i_dest
+ p_timeline
->width
+ (BTN_SPACE
>>1)) )
744 return clicked_timeline
;
746 /* is time button clicked */
747 i_dest
+= (p_timeline
->width
+ (BTN_SPACE
>>1));
748 if( (i_xpos
>= i_dest
) &&
749 (i_xpos
<= i_dest
+ p_btnTime
->width
+ (BTN_SPACE
>>1)) )
752 return clicked_Unknown
;