1 /*****************************************************************************
2 * vlcplugin.cpp: a VLC plugin for Mozilla
3 *****************************************************************************
4 * Copyright (C) 2002-2005 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Damien Fouilleul <damienf.fouilleul@laposte.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
30 #ifdef HAVE_MOZILLA_CONFIG_H
31 # include <mozilla-config.h>
34 #include "vlcplugin.h"
35 #include "control/npovlc.h"
36 #include "control/npolibvlc.h"
40 /*****************************************************************************
41 * VlcPlugin constructor and destructor
42 *****************************************************************************/
43 VlcPlugin::VlcPlugin( NPP instance
, uint16 mode
) :
51 libvlc_instance(NULL
),
60 ,i_width((unsigned)-1)
61 ,i_height((unsigned)-1)
65 memset(&npwindow
, 0, sizeof(NPWindow
));
68 static bool boolValue(const char *value
) {
69 return ( !strcmp(value
, "1") ||
70 !strcasecmp(value
, "true") ||
71 !strcasecmp(value
, "yes") );
74 NPError
VlcPlugin::init(int argc
, char* const argn
[], char* const argv
[])
76 /* prepare VLC command line */
80 /* locate VLC module path */
82 ppsz_argv
[ppsz_argc
++] = "--plugin-path";
83 ppsz_argv
[ppsz_argc
++] = "/Library/Internet Plug-Ins/VLC Plugin.plugin/"
84 "Contents/MacOS/modules";
87 DWORD i_type
, i_data
= MAX_PATH
+ 1;
88 char p_data
[MAX_PATH
+ 1];
89 if( RegOpenKeyEx( HKEY_LOCAL_MACHINE
, "Software\\VideoLAN\\VLC",
90 0, KEY_READ
, &h_key
) == ERROR_SUCCESS
)
92 if( RegQueryValueEx( h_key
, "InstallDir", 0, &i_type
,
93 (LPBYTE
)p_data
, &i_data
) == ERROR_SUCCESS
)
95 if( i_type
== REG_SZ
)
97 strcat( p_data
, "\\plugins" );
98 ppsz_argv
[ppsz_argc
++] = "--plugin-path";
99 ppsz_argv
[ppsz_argc
++] = p_data
;
102 RegCloseKey( h_key
);
104 ppsz_argv
[ppsz_argc
++] = "--no-one-instance";
106 #endif /* XP_MACOSX */
108 /* common settings */
109 ppsz_argv
[ppsz_argc
++] = "-vv";
110 ppsz_argv
[ppsz_argc
++] = "--no-stats";
111 ppsz_argv
[ppsz_argc
++] = "--no-media-library";
112 ppsz_argv
[ppsz_argc
++] = "--intf";
113 ppsz_argv
[ppsz_argc
++] = "dummy";
115 const char *progid
= NULL
;
117 /* parse plugin arguments */
118 for( int i
= 0; i
< argc
; i
++ )
120 fprintf(stderr
, "argn=%s, argv=%s\n", argn
[i
], argv
[i
]);
122 if( !strcmp( argn
[i
], "target" )
123 || !strcmp( argn
[i
], "mrl")
124 || !strcmp( argn
[i
], "filename")
125 || !strcmp( argn
[i
], "src") )
127 psz_target
= argv
[i
];
129 else if( !strcmp( argn
[i
], "autoplay")
130 || !strcmp( argn
[i
], "autostart") )
132 b_autoplay
= boolValue(argv
[i
]);
134 else if( !strcmp( argn
[i
], "fullscreen" ) )
136 if( boolValue(argv
[i
]) )
138 ppsz_argv
[ppsz_argc
++] = "--fullscreen";
142 ppsz_argv
[ppsz_argc
++] = "--no-fullscreen";
145 else if( !strcmp( argn
[i
], "mute" ) )
147 if( boolValue(argv
[i
]) )
149 ppsz_argv
[ppsz_argc
++] = "--volume";
150 ppsz_argv
[ppsz_argc
++] = "0";
153 else if( !strcmp( argn
[i
], "loop")
154 || !strcmp( argn
[i
], "autoloop") )
156 if( boolValue(argv
[i
]) )
158 ppsz_argv
[ppsz_argc
++] = "--loop";
161 ppsz_argv
[ppsz_argc
++] = "--no-loop";
164 else if( !strcmp( argn
[i
], "version")
165 || !strcmp( argn
[i
], "progid") )
171 libvlc_instance
= libvlc_new(ppsz_argc
, ppsz_argv
, NULL
);
172 if( ! libvlc_instance
)
174 return NPERR_GENERIC_ERROR
;
178 ** fetch plugin base URL, which is the URL of the page containing the plugin
179 ** this URL is used for making absolute URL from relative URL that may be
180 ** passed as an MRL argument
184 if( NPERR_NO_ERROR
== NPN_GetValue(p_browser
, NPNVWindowNPObject
, &plugin
) )
187 ** is there a better way to get that info ?
189 static const char docLocHref
[] = "document.location.href";
193 script
.utf8characters
= docLocHref
;
194 script
.utf8length
= sizeof(docLocHref
)-1;
196 if( NPN_Evaluate(p_browser
, plugin
, &script
, &result
) )
198 if( NPVARIANT_IS_STRING(result
) )
200 NPString
&location
= NPVARIANT_TO_STRING(result
);
202 psz_baseURL
= new char[location
.utf8length
+1];
205 strncpy(psz_baseURL
, location
.utf8characters
, location
.utf8length
);
206 psz_baseURL
[location
.utf8length
] = '\0';
209 NPN_ReleaseVariantValue(&result
);
211 NPN_ReleaseObject(plugin
);
216 // get absolute URL from src
217 char *psz_absurl
= getAbsoluteURL(psz_target
);
218 psz_target
= psz_absurl
? psz_absurl
: strdup(psz_target
);
221 /* assign plugin script root class */
222 if( (NULL
!= progid
) && (!strcmp(progid
, "VideoLAN.VLCPlugin.2")) )
225 p_scriptClass
= RuntimeNPClass
<LibvlcRootNPObject
>::getClass();
230 p_scriptClass
= RuntimeNPClass
<VlcNPObject
>::getClass();
233 return NPERR_NO_ERROR
;
238 /* This is really ugly but there is a deadlock when stopping a stream
239 * (in VLC_CleanUp()) because the video output is a child of the drawable but
240 * is in a different thread. */
241 static void HackStopVout( VlcPlugin
* p_plugin
)
247 int i_vlc
= libvlc_get_vlc_id(p_plugin
->libvlc_instance
);
248 VLC_VariableGet( i_vlc
, "drawable", &value
);
250 hwnd
= FindWindowEx( (HWND
)value
.i_int
, 0, 0, 0 );
253 PostMessage( hwnd
, WM_CLOSE
, 0, 0 );
257 while( PeekMessage( &msg
, (HWND
)value
.i_int
, 0, 0, PM_REMOVE
) )
259 TranslateMessage(&msg
);
260 DispatchMessage(&msg
);
262 if( FindWindowEx( (HWND
)value
.i_int
, 0, 0, 0 ) ) Sleep( 10 );
264 while( (hwnd
= FindWindowEx( (HWND
)value
.i_int
, 0, 0, 0 )) );
269 VlcPlugin::~VlcPlugin()
274 libvlc_log_close(libvlc_log
, NULL
);
275 if( libvlc_instance
)
276 libvlc_release(libvlc_instance
);
279 /*****************************************************************************
281 *****************************************************************************/
283 char *VlcPlugin::getAbsoluteURL(const char *url
)
287 // check whether URL is already absolute
288 const char *end
=strchr(url
, ':');
289 if( (NULL
!= end
) && (end
!= url
) )
291 // validate protocol header
292 const char *start
= url
;
297 while( start
!= end
)
304 || ('/' == c
)) ) /* VLC uses / to allow user to specify a demuxer */
305 // not valid protocol header, assume relative URL
309 /* we have a protocol header, therefore URL is absolute */
312 // not a valid protocol header, assume relative URL
319 size_t baseLen
= strlen(psz_baseURL
);
320 char *href
= new char[baseLen
+strlen(url
)+1];
323 /* prepend base URL */
324 strcpy(href
, psz_baseURL
);
327 ** relative url could be empty,
328 ** in which case return base URL
334 ** locate pathname part of base URL
337 /* skip over protocol part */
338 char *pathstart
= strchr(href
, ':');
342 if( '/' == *(++pathstart
) )
344 if( '/' == *(++pathstart
) )
349 /* skip over host part */
350 pathstart
= strchr(pathstart
, '/');
351 pathend
= href
+baseLen
;
354 // no path, add a / past end of url (over '\0')
361 /* baseURL is just a UNIX path */
364 /* baseURL is not an absolute path */
368 pathend
= href
+baseLen
;
371 /* relative URL made of an absolute path ? */
374 /* replace path completely */
375 strcpy(pathstart
, url
);
379 /* find last path component and replace it */
380 while( '/' != *pathend
)
384 ** if relative url path starts with one or more '../',
385 ** factor them out of href so that we return a
388 while( pathend
!= pathstart
)
396 /* relative url is just '.' */
402 /* relative url starts with './' */
411 /* relative url is '..' */
417 /* relative url starts with '../' */
425 while( '/' != *pathend
);
427 /* skip over '/' separator */
429 /* concatenate remaining base URL and relative URL */
430 strcpy(pathend
, url
);
439 int VlcPlugin::setSize(unsigned width
, unsigned height
)
441 int diff
= (width
!= i_width
) || (height
!= i_height
);
450 void VlcPlugin::showToolbar()
452 const NPWindow
& window
= getWindow();
453 Window control
= getControlWindow();
454 Display
*p_display
= ((NPSetWindowCallbackStruct
*)window
.ws_info
)->display
;
457 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/play.xpm",
458 &p_btnPlay
, NULL
, NULL
);
460 i_control_height
= __MAX( i_control_height
, p_btnPlay
->height
);
462 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/pause.xpm",
463 &p_btnPause
, NULL
, NULL
);
465 i_control_height
= __MAX( i_control_height
, p_btnPause
->height
);
467 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/stop.xpm",
468 &p_btnStop
, NULL
, NULL
);
470 i_control_height
= __MAX( i_control_height
, p_btnStop
->height
);
472 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/time_line.xpm",
473 &p_timeline
, NULL
, NULL
);
475 i_control_height
= __MAX( i_control_height
, p_timeline
->height
);
477 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/time_icon.xpm",
478 &p_btnTime
, NULL
, NULL
);
480 i_control_height
= __MAX( i_control_height
, p_btnTime
->height
);
482 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/fullscreen.xpm",
483 &p_btnFullscreen
, NULL
, NULL
);
484 if( p_btnFullscreen
)
485 i_control_height
= __MAX( i_control_height
, p_btnFullscreen
->height
);
487 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/volume_max.xpm",
488 &p_btnMute
, NULL
, NULL
);
490 i_control_height
= __MAX( i_control_height
, p_btnMute
->height
);
492 XpmReadFileToImage( p_display
, DATA_PATH
"/mozilla/volume_mute.xpm",
493 &p_btnUnmute
, NULL
, NULL
);
495 i_control_height
= __MAX( i_control_height
, p_btnUnmute
->height
);
497 if( !p_btnPlay
|| !p_btnPause
|| !p_btnStop
|| !p_timeline
||
498 !p_btnTime
|| !p_btnFullscreen
|| !p_btnMute
|| !p_btnUnmute
)
499 fprintf(stderr
, "Error: some button images not found in %s\n", DATA_PATH
);
502 void VlcPlugin::hideToolbar()
504 if( p_btnPlay
) XDestroyImage( p_btnPlay
);
505 if( p_btnPause
) XDestroyImage( p_btnPause
);
506 if( p_btnStop
) XDestroyImage( p_btnStop
);
507 if( p_timeline
) XDestroyImage( p_timeline
);
508 if( p_btnTime
) XDestroyImage( p_btnTime
);
509 if( p_btnFullscreen
) XDestroyImage( p_btnFullscreen
);
510 if( p_btnMute
) XDestroyImage( p_btnMute
);
511 if( p_btnUnmute
) XDestroyImage( p_btnUnmute
);
518 p_btnFullscreen
= NULL
;
523 void VlcPlugin::redrawToolbar()
525 libvlc_media_instance_t
*p_md
= NULL
;
526 libvlc_exception_t ex
;
527 float f_position
= 0.0;
534 const NPWindow
& window
= getWindow();
535 Window control
= getControlWindow();
536 Display
*p_display
= ((NPSetWindowCallbackStruct
*)window
.ws_info
)->display
;
538 /* get media instance */
539 libvlc_exception_init( &ex
);
540 p_md
= libvlc_playlist_get_media_instance( getVLC(), &ex
);
541 libvlc_exception_clear( &ex
);
544 libvlc_exception_init( &ex
);
545 i_playing
= libvlc_playlist_isplaying( getVLC(), &ex
);
546 libvlc_exception_clear( &ex
);
549 libvlc_exception_init(&ex
);
550 b_mute
= libvlc_audio_get_mute( getVLC(), &ex
);
551 libvlc_exception_clear( &ex
);
553 /* get movie position in % */
556 libvlc_exception_init( &ex
);
557 f_position
= libvlc_media_instance_get_position( p_md
, &ex
) * 100;
558 libvlc_exception_clear( &ex
);
560 libvlc_media_instance_release( p_md
);
562 gcv
.foreground
= BlackPixel( p_display
, 0 );
563 gc
= XCreateGC( p_display
, control
, GCForeground
, &gcv
);
565 XFillRectangle( p_display
, control
, gc
,
566 0, 0, window
.width
, i_control_height
);
567 gcv
.foreground
= WhitePixel( p_display
, 0 );
568 XChangeGC( p_display
, gc
, GCForeground
, &gcv
);
571 fprintf( stderr
, ">>>>>> is playing = %d\n", i_playing
);
572 if( p_btnPause
&& (i_playing
== 1) )
574 XPutImage( p_display
, control
, gc
, p_btnPause
, 0, 0, 4, 14,
575 p_btnPause
->width
, p_btnPause
->height
);
579 XPutImage( p_display
, control
, gc
, p_btnPlay
, 0, 0, 4, 14,
580 p_btnPlay
->width
, p_btnPlay
->height
);
584 XPutImage( p_display
, control
, gc
, p_btnStop
, 0, 0, 39, 14,
585 p_btnStop
->width
, p_btnStop
->height
);
586 if( p_btnFullscreen
)
587 XPutImage( p_display
, control
, gc
, p_btnFullscreen
, 0, 0, 67, 21,
588 p_btnFullscreen
->width
, p_btnFullscreen
->height
);
590 if( p_btnUnmute
&& b_mute
)
592 XPutImage( p_display
, control
, gc
, p_btnUnmute
, 0, 0, 94, 30,
593 p_btnUnmute
->width
, p_btnUnmute
->height
);
597 XPutImage( p_display
, control
, gc
, p_btnMute
, 0, 0, 94, 30,
598 p_btnMute
->width
, p_btnMute
->height
);
602 XPutImage( p_display
, control
, gc
, p_timeline
, 0, 0, 4, 4,
603 (window
.width
-8), p_timeline
->height
);
606 i_last_position
= (((float)window
.width
-8.0)/100.0)*f_position
;
608 XPutImage( p_display
, control
, gc
, p_btnTime
,
609 0, 0, (4+i_last_position
), 2,
610 p_btnTime
->width
, p_btnTime
->height
);
612 XFreeGC( p_display
, gc
);