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