]> git.sesse.net Git - vlc/blob - mozilla/vlcplugin.cpp
all: rewrite of mozilla plugin
[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 1
103     ppsz_argv[0] = "F:\\Cygwin\\home\\Damien\\dev\\videolan\\vlc-trunk\\vlc";
104 #endif
105
106 #endif /* XP_MACOSX */
107
108     const char *version = NULL;
109
110     /* parse plugin arguments */
111     for( int i = 0; i < argc ; i++ )
112     {
113         fprintf(stderr, "argn=%s, argv=%s\n", argn[i], argv[i]);
114
115         if( !strcmp( argn[i], "target" )
116          || !strcmp( argn[i], "mrl")
117          || !strcmp( argn[i], "filename")
118          || !strcmp( argn[i], "src") )
119         {
120             psz_target = argv[i];
121         }
122         else if( !strcmp( argn[i], "autoplay")
123               || !strcmp( argn[i], "autostart") )
124         {
125             b_autoplay = boolValue(argv[i]);
126         }
127         else if( !strcmp( argn[i], "fullscreen" ) )
128         {
129             if( boolValue(argv[i]) )
130             {
131                 ppsz_argv[ppsz_argc++] = "--fullscreen";
132             }
133             else
134             {
135                 ppsz_argv[ppsz_argc++] = "--no-fullscreen";
136             }
137         }
138         else if( !strcmp( argn[i], "mute" ) )
139         {
140             if( boolValue(argv[i]) )
141             {
142                 ppsz_argv[ppsz_argc++] = "--volume";
143                 ppsz_argv[ppsz_argc++] = "0";
144             }
145         }
146         else if( !strcmp( argn[i], "loop")
147               || !strcmp( argn[i], "autoloop") )
148         {
149             if( boolValue(argv[i]) )
150             {
151                 ppsz_argv[ppsz_argc++] = "--loop";
152             }
153             else {
154                 ppsz_argv[ppsz_argc++] = "--no-loop";
155             }
156         }
157         else if( !strcmp( argn[i], "version") )
158         {
159             version = argv[i];
160         }
161     }
162
163     libvlc_instance = libvlc_new(ppsz_argc, ppsz_argv, NULL);
164     if( ! libvlc_instance )
165     {
166         return NPERR_GENERIC_ERROR;
167     }
168
169     /*
170     ** fetch plugin base URL, which is the URL of the page containing the plugin
171     ** this URL is used for making absolute URL from relative URL that may be
172     ** passed as an MRL argument
173     */
174     NPObject *plugin;
175
176     if( NPERR_NO_ERROR == NPN_GetValue(p_browser, NPNVWindowNPObject, &plugin) )
177     {
178         /*
179         ** is there a better way to get that info ?
180         */
181         static const char docLocHref[] = "document.location.href";
182         NPString script;
183         NPVariant result;
184
185         script.utf8characters = docLocHref;
186         script.utf8length = sizeof(docLocHref)-1;
187
188         if( NPN_Evaluate(p_browser, plugin, &script, &result) )
189         {
190             if( NPVARIANT_IS_STRING(result) )
191             {
192                 NPString &location = NPVARIANT_TO_STRING(result);
193
194                 psz_baseURL = new char[location.utf8length+1];
195                 if( psz_baseURL )
196                 {
197                     strncpy(psz_baseURL, location.utf8characters, location.utf8length);
198                     psz_baseURL[location.utf8length] = '\0';
199                 }
200             }
201             NPN_ReleaseVariantValue(&result);
202         }
203         NPN_ReleaseObject(plugin);
204     }
205
206     if( psz_target )
207     {
208         // get absolute URL from src
209         psz_target = getAbsoluteURL(psz_target);
210     }
211
212     /* assign plugin script root class */
213     if( (NULL != version) && (!strcmp(version, "VideoLAN.VLCPlugin.2")) )
214     {
215         /* new APIs */
216         scriptClass = new RuntimeNPClass<LibvlcRootNPObject>();
217     }
218     else
219     {
220         /* legacy APIs */
221         scriptClass = new RuntimeNPClass<VlcNPObject>();
222     }
223
224     return NPERR_NO_ERROR;
225 }
226
227 #if 0
228 #ifdef XP_WIN
229 /* This is really ugly but there is a deadlock when stopping a stream
230  * (in VLC_CleanUp()) because the video output is a child of the drawable but
231  * is in a different thread. */
232 static void HackStopVout( VlcPlugin* p_plugin )
233 {
234     MSG msg;
235     HWND hwnd;
236     vlc_value_t value;
237
238     int i_vlc = libvlc_get_vlc_id(p_plugin->libvlc_instance);
239     VLC_VariableGet( i_vlc, "drawable", &value );
240
241     hwnd = FindWindowEx( (HWND)value.i_int, 0, 0, 0 );
242     if( !hwnd ) return;
243
244     PostMessage( hwnd, WM_CLOSE, 0, 0 );
245
246     do
247     {
248         while( PeekMessage( &msg, (HWND)value.i_int, 0, 0, PM_REMOVE ) )
249         {
250             TranslateMessage(&msg);
251             DispatchMessage(&msg);
252         }
253         if( FindWindowEx( (HWND)value.i_int, 0, 0, 0 ) ) Sleep( 10 );
254     }
255     while( (hwnd = FindWindowEx( (HWND)value.i_int, 0, 0, 0 )) );
256 }
257 #endif /* XP_WIN */
258 #endif
259
260 VlcPlugin::~VlcPlugin()
261 {
262     delete psz_baseURL;
263     delete psz_target;
264     if( libvlc_instance )
265         libvlc_destroy(libvlc_instance);
266 }
267
268 /*****************************************************************************
269  * VlcPlugin methods
270  *****************************************************************************/
271
272 char *VlcPlugin::getAbsoluteURL(const char *url)
273 {
274     if( NULL != url )
275     {
276         // check whether URL is already absolute
277         const char *end=strchr(url, ':');
278         if( (NULL != end) && (end != url) )
279         {
280             // validate protocol header
281             const char *start = url;
282             while( start != end ) {
283                 char c = *start | 0x20;
284                 if( (c < 'a') || (c > 'z') )
285                     // not valid protocol header, assume relative URL
286                     break;
287                 ++start;
288             }
289             /* we have a protocol header, therefore URL is absolute */
290             return strdup(url);
291         }
292
293         if( psz_baseURL )
294         {
295             size_t baseLen = strlen(psz_baseURL);
296             char *href = new char[baseLen+strlen(url)];
297             if( href )
298             {
299                 /* prepend base URL */
300                 strcpy(href, psz_baseURL);
301
302                 /*
303                 ** relative url could be empty,
304                 ** in which case return base URL
305                 */
306                 if( '\0' == *url )
307                     return href;
308
309                 /*
310                 ** locate pathname part of base URL
311                 */
312
313                 /* skip over protocol part  */
314                 char *pathstart = strchr(href, ':');
315                 char *pathend;
316                 if( '/' == *(++pathstart) )
317                 {
318                     if( '/' == *(++pathstart) )
319                     {
320                         ++pathstart;
321                     }
322                 }
323                 /* skip over host part */
324                 pathstart = strchr(pathstart, '/');
325                 pathend = href+baseLen;
326                 if( ! pathstart )
327                 {
328                     // no path, add a / past end of url (over '\0')
329                     pathstart = pathend;
330                     *pathstart = '/';
331                 }
332
333                 /* relative URL made of an absolute path ? */
334                 if( '/' == *url )
335                 {
336                     /* replace path completely */
337                     strcpy(pathstart, url);
338                     return href;
339                 }
340
341                 /* find last path component and replace it */ 
342                 while( '/' != *pathend) --pathend;
343
344                 /*
345                 ** if relative url path starts with one or more '../',
346                 ** factor them out of href so that we return a
347                 ** normalized URL
348                 */
349                 while( pathend != pathstart )
350                 {
351                     const char *p = url;
352                     if( '.' != *p )
353                         break;
354                     ++p;
355                     if( '.' != *p ) 
356                         break;
357                     ++p;
358                     if( '/' != *p ) 
359                         break;
360                     ++p;
361                     url = p;
362                     while( '/' != *pathend ) --pathend;
363                 }
364                 /* concatenate remaining base URL and relative URL */
365                 strcpy(pathend+1, url);
366             }
367             return href;
368         }
369     }
370     return NULL;
371 }
372
373 #if XP_UNIX
374 int  VlcPlugin::setSize(unsigned width, unsigned height)
375 {
376     int diff = (width != i_width) || (height != i_height);
377
378     i_width = width;
379     i_height = height;
380
381     /* return size */
382     return diff;
383 }
384 #endif
385