]> git.sesse.net Git - vlc/blob - mozilla/vlcplugin.cpp
- mozilla: cleaned up configuration arguments
[vlc] / mozilla / vlcplugin.cpp
1 /*****************************************************************************
2  * vlcplugin.cpp: a VLC plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Damien Fouilleul <damienf.fouilleul@laposte.net>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "config.h"
29
30 #ifdef HAVE_MOZILLA_CONFIG_H
31 #   include <mozilla-config.h>
32 #endif
33
34 #include "vlcplugin.h"
35 #include "control/npovlc.h"
36 #include "control/npolibvlc.h"
37
38 /*****************************************************************************
39  * VlcPlugin constructor and destructor
40  *****************************************************************************/
41 VlcPlugin::VlcPlugin( NPP instance, uint16 mode ) :
42     i_npmode(mode),
43     b_stream(0),
44     b_autoplay(0),
45     psz_target(NULL),
46     libvlc_instance(NULL),
47     scriptClass(NULL),
48     p_browser(instance),
49     psz_baseURL(NULL)
50 #if XP_WIN
51     ,pf_wndproc(NULL)
52 #endif
53 #if XP_UNIX
54     ,i_width((unsigned)-1)
55     ,i_height((unsigned)-1)
56 #endif
57 {
58     memset(&npwindow, 0, sizeof(NPWindow));
59 }
60
61 static int boolValue(const char *value) {
62     return ( !strcmp(value, "1") || 
63              !strcasecmp(value, "true") ||
64              !strcasecmp(value, "yes") );
65 }
66
67 NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
68 {
69     /* prepare VLC command line */
70     char *ppsz_argv[32] = { "vlc" };
71     int ppsz_argc = 1;
72
73     /* locate VLC module path */
74 #ifdef XP_MACOSX
75     ppsz_argv[ppsz_argc++] = "--plugin-path";
76     ppsz_argv[ppsz_argc++] = "/Library/Internet Plug-Ins/VLC Plugin.plugin/"
77                              "Contents/MacOS/modules";
78 #elif defined(XP_WIN)
79     HKEY h_key;
80     DWORD i_type, i_data = MAX_PATH + 1;
81     char p_data[MAX_PATH + 1];
82     if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
83                       0, KEY_READ, &h_key ) == ERROR_SUCCESS )
84     {
85          if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
86                               (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
87          {
88              if( i_type == REG_SZ )
89              {
90                  strcat( p_data, "\\plugins" );
91                  ppsz_argv[ppsz_argc++] = "--plugin-path";
92                  ppsz_argv[ppsz_argc++] = p_data;
93              }
94          }
95          RegCloseKey( h_key );
96     }
97     ppsz_argv[ppsz_argc++] = "--no-one-instance";
98     if( IsDebuggerPresent() )
99     {
100         /*
101         ** VLC default threading mechanism is designed to be as compatible
102         ** with POSIX as possible. However when debugged on win32, threads
103         ** lose signals and eventually VLC get stuck during initialization.
104         ** threading support can be configured to be more debugging friendly
105         ** but it will be less compatible with POSIX.
106         ** This is done by initializing with the following options:
107         */
108         ppsz_argv[ppsz_argc++] = "--fast-mutex";
109         ppsz_argv[ppsz_argc++] = "--win9x-cv-method=1";
110     }
111
112
113 #if 0
114     ppsz_argv[0] = "C:\\Cygwin\\home\\damienf\\vlc-trunk\\vlc";
115 #endif
116
117 #endif /* XP_MACOSX */
118
119     /* common settings */
120     ppsz_argv[ppsz_argc++] = "-vv";
121     ppsz_argv[ppsz_argc++] = "--no-stats";
122     ppsz_argv[ppsz_argc++] = "--no-media-library";
123     ppsz_argv[ppsz_argc++] = "--intf";
124     ppsz_argv[ppsz_argc++] = "dummy";
125
126     const char *version = NULL;
127
128     /* parse plugin arguments */
129     for( int i = 0; i < argc ; i++ )
130     {
131         fprintf(stderr, "argn=%s, argv=%s\n", argn[i], argv[i]);
132
133         if( !strcmp( argn[i], "target" )
134          || !strcmp( argn[i], "mrl")
135          || !strcmp( argn[i], "filename")
136          || !strcmp( argn[i], "src") )
137         {
138             psz_target = argv[i];
139         }
140         else if( !strcmp( argn[i], "autoplay")
141               || !strcmp( argn[i], "autostart") )
142         {
143             b_autoplay = boolValue(argv[i]);
144         }
145         else if( !strcmp( argn[i], "fullscreen" ) )
146         {
147             if( boolValue(argv[i]) )
148             {
149                 ppsz_argv[ppsz_argc++] = "--fullscreen";
150             }
151             else
152             {
153                 ppsz_argv[ppsz_argc++] = "--no-fullscreen";
154             }
155         }
156         else if( !strcmp( argn[i], "mute" ) )
157         {
158             if( boolValue(argv[i]) )
159             {
160                 ppsz_argv[ppsz_argc++] = "--volume";
161                 ppsz_argv[ppsz_argc++] = "0";
162             }
163         }
164         else if( !strcmp( argn[i], "loop")
165               || !strcmp( argn[i], "autoloop") )
166         {
167             if( boolValue(argv[i]) )
168             {
169                 ppsz_argv[ppsz_argc++] = "--loop";
170             }
171             else {
172                 ppsz_argv[ppsz_argc++] = "--no-loop";
173             }
174         }
175         else if( !strcmp( argn[i], "version") )
176         {
177             version = argv[i];
178         }
179     }
180
181     libvlc_instance = libvlc_new(ppsz_argc, ppsz_argv, NULL);
182     if( ! libvlc_instance )
183     {
184         return NPERR_GENERIC_ERROR;
185     }
186
187     /*
188     ** fetch plugin base URL, which is the URL of the page containing the plugin
189     ** this URL is used for making absolute URL from relative URL that may be
190     ** passed as an MRL argument
191     */
192     NPObject *plugin;
193
194     if( NPERR_NO_ERROR == NPN_GetValue(p_browser, NPNVWindowNPObject, &plugin) )
195     {
196         /*
197         ** is there a better way to get that info ?
198         */
199         static const char docLocHref[] = "document.location.href";
200         NPString script;
201         NPVariant result;
202
203         script.utf8characters = docLocHref;
204         script.utf8length = sizeof(docLocHref)-1;
205
206         if( NPN_Evaluate(p_browser, plugin, &script, &result) )
207         {
208             if( NPVARIANT_IS_STRING(result) )
209             {
210                 NPString &location = NPVARIANT_TO_STRING(result);
211
212                 psz_baseURL = new char[location.utf8length+1];
213                 if( psz_baseURL )
214                 {
215                     strncpy(psz_baseURL, location.utf8characters, location.utf8length);
216                     psz_baseURL[location.utf8length] = '\0';
217                 }
218             }
219             NPN_ReleaseVariantValue(&result);
220         }
221         NPN_ReleaseObject(plugin);
222     }
223
224     if( psz_target )
225     {
226         // get absolute URL from src
227         psz_target = getAbsoluteURL(psz_target);
228     }
229
230     /* assign plugin script root class */
231     if( (NULL != version) && (!strcmp(version, "VideoLAN.VLCPlugin.2")) )
232     {
233         /* new APIs */
234         scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
235     }
236     else
237     {
238         /* legacy APIs */
239         scriptClass = RuntimeNPClass<VlcNPObject>::getClass();
240     }
241
242     return NPERR_NO_ERROR;
243 }
244
245 #if 0
246 #ifdef XP_WIN
247 /* This is really ugly but there is a deadlock when stopping a stream
248  * (in VLC_CleanUp()) because the video output is a child of the drawable but
249  * is in a different thread. */
250 static void HackStopVout( VlcPlugin* p_plugin )
251 {
252     MSG msg;
253     HWND hwnd;
254     vlc_value_t value;
255
256     int i_vlc = libvlc_get_vlc_id(p_plugin->libvlc_instance);
257     VLC_VariableGet( i_vlc, "drawable", &value );
258
259     hwnd = FindWindowEx( (HWND)value.i_int, 0, 0, 0 );
260     if( !hwnd ) return;
261
262     PostMessage( hwnd, WM_CLOSE, 0, 0 );
263
264     do
265     {
266         while( PeekMessage( &msg, (HWND)value.i_int, 0, 0, PM_REMOVE ) )
267         {
268             TranslateMessage(&msg);
269             DispatchMessage(&msg);
270         }
271         if( FindWindowEx( (HWND)value.i_int, 0, 0, 0 ) ) Sleep( 10 );
272     }
273     while( (hwnd = FindWindowEx( (HWND)value.i_int, 0, 0, 0 )) );
274 }
275 #endif /* XP_WIN */
276 #endif
277
278 VlcPlugin::~VlcPlugin()
279 {
280     delete psz_baseURL;
281     delete psz_target;
282     if( libvlc_instance )
283         libvlc_destroy(libvlc_instance, NULL );
284 }
285
286 /*****************************************************************************
287  * VlcPlugin methods
288  *****************************************************************************/
289
290 char *VlcPlugin::getAbsoluteURL(const char *url)
291 {
292     if( NULL != url )
293     {
294         // check whether URL is already absolute
295         const char *end=strchr(url, ':');
296         if( (NULL != end) && (end != url) )
297         {
298             // validate protocol header
299             const char *start = url;
300             while( start != end ) {
301                 char c = *start | 0x20;
302                 if( (c < 'a') || (c > 'z') )
303                     // not valid protocol header, assume relative URL
304                     break;
305                 ++start;
306             }
307             /* we have a protocol header, therefore URL is absolute */
308             return strdup(url);
309         }
310
311         if( psz_baseURL )
312         {
313             size_t baseLen = strlen(psz_baseURL);
314             char *href = new char[baseLen+strlen(url)];
315             if( href )
316             {
317                 /* prepend base URL */
318                 strcpy(href, psz_baseURL);
319
320                 /*
321                 ** relative url could be empty,
322                 ** in which case return base URL
323                 */
324                 if( '\0' == *url )
325                     return href;
326
327                 /*
328                 ** locate pathname part of base URL
329                 */
330
331                 /* skip over protocol part  */
332                 char *pathstart = strchr(href, ':');
333                 char *pathend;
334                 if( '/' == *(++pathstart) )
335                 {
336                     if( '/' == *(++pathstart) )
337                     {
338                         ++pathstart;
339                     }
340                 }
341                 /* skip over host part */
342                 pathstart = strchr(pathstart, '/');
343                 pathend = href+baseLen;
344                 if( ! pathstart )
345                 {
346                     // no path, add a / past end of url (over '\0')
347                     pathstart = pathend;
348                     *pathstart = '/';
349                 }
350
351                 /* relative URL made of an absolute path ? */
352                 if( '/' == *url )
353                 {
354                     /* replace path completely */
355                     strcpy(pathstart, url);
356                     return href;
357                 }
358
359                 /* find last path component and replace it */ 
360                 while( '/' != *pathend) --pathend;
361
362                 /*
363                 ** if relative url path starts with one or more '../',
364                 ** factor them out of href so that we return a
365                 ** normalized URL
366                 */
367                 while( pathend != pathstart )
368                 {
369                     const char *p = url;
370                     if( '.' != *p )
371                         break;
372                     ++p;
373                     if( '.' != *p ) 
374                         break;
375                     ++p;
376                     if( '/' != *p ) 
377                         break;
378                     ++p;
379                     url = p;
380                     while( '/' != *pathend ) --pathend;
381                 }
382                 /* concatenate remaining base URL and relative URL */
383                 strcpy(pathend+1, url);
384             }
385             return href;
386         }
387     }
388     return NULL;
389 }
390
391 #if XP_UNIX
392 int  VlcPlugin::setSize(unsigned width, unsigned height)
393 {
394     int diff = (width != i_width) || (height != i_height);
395
396     i_width = width;
397     i_height = height;
398
399     /* return size */
400     return diff;
401 }
402 #endif
403