Dutch l10n update by Myckel Habets
[vlc.git] / projects / mozilla / vlcplugin.cpp
blobac2cbb64e441a94b1dcb1c9a041c1ff5d76d62d9
1 /*****************************************************************************
2 * vlcplugin.cpp: a VLC plugin for Mozilla
3 *****************************************************************************
4 * Copyright (C) 2002-2005 the VideoLAN team
5 * $Id$
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #include "config.h"
30 #ifdef HAVE_MOZILLA_CONFIG_H
31 # include <mozilla-config.h>
32 #endif
34 #include "vlcplugin.h"
35 #include "control/npovlc.h"
36 #include "control/npolibvlc.h"
38 #include <ctype.h>
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 #if XP_UNIX
48 i_control_height(45),
49 #endif
50 psz_target(NULL),
51 libvlc_instance(NULL),
52 libvlc_log(NULL),
53 p_scriptClass(NULL),
54 p_browser(instance),
55 psz_baseURL(NULL)
56 #if XP_WIN
57 ,pf_wndproc(NULL)
58 #endif
59 #if XP_UNIX
60 ,i_width((unsigned)-1)
61 ,i_height((unsigned)-1)
62 ,i_last_position(0)
63 #endif
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 */
77 char *ppsz_argv[32];
78 int ppsz_argc = 0;
80 /* locate VLC module path */
81 #ifdef XP_MACOSX
82 ppsz_argv[ppsz_argc++] = "--plugin-path";
83 ppsz_argv[ppsz_argc++] = "/Library/Internet Plug-Ins/VLC Plugin.plugin/"
84 "Contents/MacOS/modules";
85 #elif defined(XP_WIN)
86 HKEY h_key;
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";
140 else
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";
160 else {
161 ppsz_argv[ppsz_argc++] = "--no-loop";
164 else if( !strcmp( argn[i], "version")
165 || !strcmp( argn[i], "progid") )
167 progid = argv[i];
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
182 NPObject *plugin;
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";
190 NPString script;
191 NPVariant result;
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];
203 if( psz_baseURL )
205 strncpy(psz_baseURL, location.utf8characters, location.utf8length);
206 psz_baseURL[location.utf8length] = '\0';
209 NPN_ReleaseVariantValue(&result);
211 NPN_ReleaseObject(plugin);
214 if( psz_target )
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")) )
224 /* new APIs */
225 p_scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
227 else
229 /* legacy APIs */
230 p_scriptClass = RuntimeNPClass<VlcNPObject>::getClass();
233 return NPERR_NO_ERROR;
236 #if 0
237 #ifdef XP_WIN
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 )
243 MSG msg;
244 HWND hwnd;
245 vlc_value_t value;
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 );
251 if( !hwnd ) return;
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 )) );
266 #endif /* XP_WIN */
267 #endif
269 VlcPlugin::~VlcPlugin()
271 delete psz_baseURL;
272 delete psz_target;
273 if( libvlc_log )
274 libvlc_log_close(libvlc_log, NULL);
275 if( libvlc_instance )
276 libvlc_release(libvlc_instance);
279 /*****************************************************************************
280 * VlcPlugin methods
281 *****************************************************************************/
283 char *VlcPlugin::getAbsoluteURL(const char *url)
285 if( NULL != 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;
293 char c = *start;
294 if( isalpha(c) )
296 ++start;
297 while( start != end )
299 c = *start;
300 if( ! (isalnum(c)
301 || ('-' == c)
302 || ('+' == c)
303 || ('.' == c)
304 || ('/' == c)) ) /* VLC uses / to allow user to specify a demuxer */
305 // not valid protocol header, assume relative URL
306 goto relativeurl;
307 ++start;
309 /* we have a protocol header, therefore URL is absolute */
310 return strdup(url);
312 // not a valid protocol header, assume relative URL
315 relativeurl:
317 if( psz_baseURL )
319 size_t baseLen = strlen(psz_baseURL);
320 char *href = new char[baseLen+strlen(url)+1];
321 if( href )
323 /* prepend base URL */
324 strcpy(href, psz_baseURL);
327 ** relative url could be empty,
328 ** in which case return base URL
330 if( '\0' == *url )
331 return href;
334 ** locate pathname part of base URL
337 /* skip over protocol part */
338 char *pathstart = strchr(href, ':');
339 char *pathend;
340 if( pathstart )
342 if( '/' == *(++pathstart) )
344 if( '/' == *(++pathstart) )
346 ++pathstart;
349 /* skip over host part */
350 pathstart = strchr(pathstart, '/');
351 pathend = href+baseLen;
352 if( ! pathstart )
354 // no path, add a / past end of url (over '\0')
355 pathstart = pathend;
356 *pathstart = '/';
359 else
361 /* baseURL is just a UNIX path */
362 if( '/' != *href )
364 /* baseURL is not an absolute path */
365 return NULL;
367 pathstart = href;
368 pathend = href+baseLen;
371 /* relative URL made of an absolute path ? */
372 if( '/' == *url )
374 /* replace path completely */
375 strcpy(pathstart, url);
376 return href;
379 /* find last path component and replace it */
380 while( '/' != *pathend)
381 --pathend;
384 ** if relative url path starts with one or more '../',
385 ** factor them out of href so that we return a
386 ** normalized URL
388 while( pathend != pathstart )
390 const char *p = url;
391 if( '.' != *p )
392 break;
393 ++p;
394 if( '\0' == *p )
396 /* relative url is just '.' */
397 url = p;
398 break;
400 if( '/' == *p )
402 /* relative url starts with './' */
403 url = ++p;
404 continue;
406 if( '.' != *p )
407 break;
408 ++p;
409 if( '\0' == *p )
411 /* relative url is '..' */
413 else
415 if( '/' != *p )
416 break;
417 /* relative url starts with '../' */
418 ++p;
420 url = p;
423 --pathend;
425 while( '/' != *pathend );
427 /* skip over '/' separator */
428 ++pathend;
429 /* concatenate remaining base URL and relative URL */
430 strcpy(pathend, url);
432 return href;
435 return NULL;
438 #if XP_UNIX
439 int VlcPlugin::setSize(unsigned width, unsigned height)
441 int diff = (width != i_width) || (height != i_height);
443 i_width = width;
444 i_height = height;
446 /* return size */
447 return diff;
450 void VlcPlugin::showToolbar()
452 const NPWindow& window = getWindow();
453 Window control = getControlWindow();
454 Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
456 /* load icons */
457 XpmReadFileToImage( p_display, DATA_PATH "/mozilla/play.xpm",
458 &p_btnPlay, NULL, NULL);
459 if( p_btnPlay )
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);
464 if( p_btnPause )
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 );
469 if( p_btnStop )
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);
474 if( p_timeline )
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);
479 if( p_btnTime )
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);
489 if( p_btnMute )
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);
494 if( p_btnUnmute )
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 );
513 p_btnPlay = NULL;
514 p_btnPause = NULL;
515 p_btnStop = NULL;
516 p_timeline = NULL;
517 p_btnTime = NULL;
518 p_btnFullscreen = NULL;
519 p_btnMute = NULL;
520 p_btnUnmute = NULL;
523 void VlcPlugin::redrawToolbar()
525 libvlc_media_instance_t *p_md = NULL;
526 libvlc_exception_t ex;
527 float f_position = 0.0;
528 int i_playing = 0;
529 bool b_mute = false;
531 GC gc;
532 XGCValues gcv;
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 );
543 /* get isplaying */
544 libvlc_exception_init( &ex );
545 i_playing = libvlc_playlist_isplaying( getVLC(), &ex );
546 libvlc_exception_clear( &ex );
548 /* get mute info */
549 libvlc_exception_init(&ex);
550 b_mute = libvlc_audio_get_mute( getVLC(), &ex );
551 libvlc_exception_clear( &ex );
553 /* get movie position in % */
554 if( i_playing == 1 )
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 );
570 /* position icons */
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 );
577 else if( p_btnPlay )
579 XPutImage( p_display, control, gc, p_btnPlay, 0, 0, 4, 14,
580 p_btnPlay->width, p_btnPlay->height );
583 if( p_btnStop )
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 );
595 else if( p_btnMute )
597 XPutImage( p_display, control, gc, p_btnMute, 0, 0, 94, 30,
598 p_btnMute->width, p_btnMute->height );
601 if( p_timeline )
602 XPutImage( p_display, control, gc, p_timeline, 0, 0, 4, 4,
603 (window.width-8), p_timeline->height );
605 if( f_position > 0 )
606 i_last_position = (((float)window.width-8.0)/100.0)*f_position;
607 if( p_btnTime )
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 );
614 #endif