]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
mozilla plugin: rework events listeners to dom level 2 type, sort of.
[vlc] / projects / mozilla / control / npolibvlc.cpp
1 /*****************************************************************************
2  * npolibvlc.cpp: official Javascript APIs
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * Copyright (C) 2010 M2X BV
6  *
7  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
8  *          JP Dinger <jpd@videolan.org>
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 along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 /* Mozilla stuff */
32 #ifdef HAVE_MOZILLA_CONFIG_H
33 #   include <mozilla-config.h>
34 #endif
35
36 #include "vlcplugin.h"
37 #include "npolibvlc.h"
38
39 #include "position.h"
40
41 /*
42 ** Local helper macros and function
43 */
44 #define COUNTNAMES(a,b,c) const int a::b = sizeof(a::c)/sizeof(NPUTF8 *)
45 #define RETURN_ON_EXCEPTION(this,ex) \
46     do { if( libvlc_exception_raised(&ex) ) \
47     { \
48         NPN_SetException(this, libvlc_errmsg()); \
49         libvlc_exception_clear(&ex); \
50         return INVOKERESULT_GENERIC_ERROR; \
51     } } while(false)
52
53 #define ERROR_EVENT_NOT_FOUND "ERROR: One or more events could not be found."
54 #define ERROR_API_VERSION "ERROR: NPAPI version not high enough. (Gecko >= 1.9 needed)"
55
56 // Make a copy of an NPVariant.
57 NPVariant copyNPVariant(const NPVariant& original)
58 {
59     NPVariant res;
60
61     if (NPVARIANT_IS_STRING(original))
62         STRINGZ_TO_NPVARIANT(strdup(NPVARIANT_TO_STRING(original).utf8characters), res);
63     else if (NPVARIANT_IS_INT32(original))
64         INT32_TO_NPVARIANT(NPVARIANT_TO_INT32(original), res);
65     else if (NPVARIANT_IS_DOUBLE(original))
66         DOUBLE_TO_NPVARIANT(NPVARIANT_TO_DOUBLE(original), res);
67     else if (NPVARIANT_IS_OBJECT(original))
68     {
69         NPObject *obj = NPVARIANT_TO_OBJECT(original);
70         NPN_RetainObject(obj);
71         OBJECT_TO_NPVARIANT(obj, res);
72     }
73     else if (NPVARIANT_IS_BOOLEAN(original))
74         BOOLEAN_TO_NPVARIANT(NPVARIANT_TO_BOOLEAN(original), res);
75
76     return res;
77 }
78
79 /*
80 ** implementation of libvlc root object
81 */
82
83 LibvlcRootNPObject::~LibvlcRootNPObject()
84 {
85     /*
86     ** When the plugin is destroyed, firefox takes it upon itself to
87     ** destroy all 'live' script objects and ignores refcounting.
88     ** Therefore we cannot safely assume that refcounting will control
89     ** lifespan of objects. Hence they are only lazily created on
90     ** request, so that firefox can take ownership, and are not released
91     ** when the plugin is destroyed.
92     */
93     if( isValid() )
94     {
95         if( audioObj    ) NPN_ReleaseObject(audioObj);
96         if( inputObj    ) NPN_ReleaseObject(inputObj);
97         if( playlistObj ) NPN_ReleaseObject(playlistObj);
98         if( subtitleObj ) NPN_ReleaseObject(subtitleObj);
99         if( videoObj    ) NPN_ReleaseObject(videoObj);
100     }
101 }
102
103 const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
104 {
105     "audio",
106     "input",
107     "playlist",
108     "subtitle",
109     "video",
110     "VersionInfo",
111 };
112 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
113
114 enum LibvlcRootNPObjectPropertyIds
115 {
116     ID_root_audio = 0,
117     ID_root_input,
118     ID_root_playlist,
119     ID_root_subtitle,
120     ID_root_video,
121     ID_root_VersionInfo,
122 };
123
124 RuntimeNPObject::InvokeResult
125 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
126 {
127     /* is plugin still running */
128     if( isPluginRunning() )
129     {
130         switch( index )
131         {
132             case ID_root_audio:
133                 InstantObj<LibvlcAudioNPObject>( audioObj );
134                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
135                 return INVOKERESULT_NO_ERROR;
136             case ID_root_input:
137                 InstantObj<LibvlcInputNPObject>( inputObj );
138                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
139                 return INVOKERESULT_NO_ERROR;
140             case ID_root_playlist:
141                 InstantObj<LibvlcPlaylistNPObject>( playlistObj );
142                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
143                 return INVOKERESULT_NO_ERROR;
144             case ID_root_subtitle:
145                 InstantObj<LibvlcSubtitleNPObject>( subtitleObj );
146                 OBJECT_TO_NPVARIANT(NPN_RetainObject(subtitleObj), result);
147                 return INVOKERESULT_NO_ERROR;
148             case ID_root_video:
149                 InstantObj<LibvlcVideoNPObject>( videoObj );
150                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
151                 return INVOKERESULT_NO_ERROR;
152             case ID_root_VersionInfo:
153                 return invokeResultString(libvlc_get_version(),result);
154             default:
155                 ;
156         }
157     }
158     return INVOKERESULT_GENERIC_ERROR;
159 }
160
161 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
162 {
163     "versionInfo",
164     "addEventListener",
165     "removeEventListener",
166 };
167 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
168
169 enum LibvlcRootNPObjectMethodIds
170 {
171     ID_root_versionInfo,
172     ID_root_addeventlistener,
173     ID_root_removeeventlistener,
174 };
175
176 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
177                   const NPVariant *args, uint32_t argCount, NPVariant &result)
178 {
179     /* is plugin still running */
180     if( !isPluginRunning() )
181         return INVOKERESULT_GENERIC_ERROR;
182
183     libvlc_exception_t ex;
184     libvlc_exception_init(&ex);
185
186     switch( index )
187     {
188     case ID_root_versionInfo:
189         if( 0 != argCount )
190             return INVOKERESULT_NO_SUCH_METHOD;
191         return invokeResultString(libvlc_get_version(),result);
192
193     case ID_root_addeventlistener:
194     case ID_root_removeeventlistener:
195         if( (3 != argCount) ||
196             !NPVARIANT_IS_STRING(args[0]) ||
197             !NPVARIANT_IS_OBJECT(args[1]) ||
198             !NPVARIANT_IS_BOOLEAN(args[2]) )
199             break;
200
201         if( !VlcPlugin::canUseEventListener() )
202         {
203             NPN_SetException(this, ERROR_API_VERSION);
204             return INVOKERESULT_GENERIC_ERROR;
205         }
206
207         NPObject *listener = NPVARIANT_TO_OBJECT(args[1]);
208         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
209
210         bool b;
211         if(ID_root_removeeventlistener!=index)
212             b = p_plugin->events.insert(NPVARIANT_TO_STRING(args[0]),
213                                      listener, NPVARIANT_TO_BOOLEAN(args[2]));
214         else
215             b = p_plugin->events.remove(NPVARIANT_TO_STRING(args[0]),
216                                      listener, NPVARIANT_TO_BOOLEAN(args[2]));
217
218         VOID_TO_NPVARIANT(result);
219
220         return b ? INVOKERESULT_NO_ERROR : INVOKERESULT_GENERIC_ERROR;
221     }
222     return INVOKERESULT_NO_SUCH_METHOD;
223 }
224
225 /*
226 ** implementation of libvlc audio object
227 */
228
229 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
230 {
231     "mute",
232     "volume",
233     "track",
234     "count",
235     "channel",
236 };
237 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
238
239 enum LibvlcAudioNPObjectPropertyIds
240 {
241     ID_audio_mute,
242     ID_audio_volume,
243     ID_audio_track,
244     ID_audio_count,
245     ID_audio_channel,
246 };
247
248 RuntimeNPObject::InvokeResult
249 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
250 {
251     /* is plugin still running */
252     if( isPluginRunning() )
253     {
254         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
255         libvlc_exception_t ex;
256         libvlc_exception_init(&ex);
257
258         switch( index )
259         {
260             case ID_audio_mute:
261             {
262                 bool muted = libvlc_audio_get_mute(p_plugin->getVLC());
263                 BOOLEAN_TO_NPVARIANT(muted, result);
264                 return INVOKERESULT_NO_ERROR;
265             }
266             case ID_audio_volume:
267             {
268                 int volume = libvlc_audio_get_volume(p_plugin->getVLC());
269                 INT32_TO_NPVARIANT(volume, result);
270                 return INVOKERESULT_NO_ERROR;
271             }
272             case ID_audio_track:
273             {
274                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
275                 RETURN_ON_EXCEPTION(this,ex);
276                 int track = libvlc_audio_get_track(p_md, &ex);
277                 RETURN_ON_EXCEPTION(this,ex);
278                 INT32_TO_NPVARIANT(track, result);
279                 return INVOKERESULT_NO_ERROR;
280             }
281             case ID_audio_count:
282             {
283                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
284                 RETURN_ON_EXCEPTION(this,ex);
285                 // get the number of audio track available
286                 int i_track = libvlc_audio_get_track_count(p_md, &ex);
287                 RETURN_ON_EXCEPTION(this,ex);
288                 // return it
289                 INT32_TO_NPVARIANT(i_track, result);
290                 return INVOKERESULT_NO_ERROR;
291             }
292             case ID_audio_channel:
293             {
294                 int channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
295                 RETURN_ON_EXCEPTION(this,ex);
296                 INT32_TO_NPVARIANT(channel, result);
297                 return INVOKERESULT_NO_ERROR;
298             }
299             default:
300                 ;
301         }
302     }
303     return INVOKERESULT_GENERIC_ERROR;
304 }
305
306 RuntimeNPObject::InvokeResult
307 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
308 {
309     /* is plugin still running */
310     if( isPluginRunning() )
311     {
312         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
313         libvlc_exception_t ex;
314         libvlc_exception_init(&ex);
315
316         switch( index )
317         {
318             case ID_audio_mute:
319                 if( NPVARIANT_IS_BOOLEAN(value) )
320                 {
321                     libvlc_audio_set_mute(p_plugin->getVLC(),
322                                           NPVARIANT_TO_BOOLEAN(value));
323                     return INVOKERESULT_NO_ERROR;
324                 }
325                 return INVOKERESULT_INVALID_VALUE;
326             case ID_audio_volume:
327                 if( isNumberValue(value) )
328                 {
329                     libvlc_audio_set_volume(p_plugin->getVLC(),
330                                             numberValue(value), &ex);
331                     RETURN_ON_EXCEPTION(this,ex);
332                     return INVOKERESULT_NO_ERROR;
333                 }
334                 return INVOKERESULT_INVALID_VALUE;
335             case ID_audio_track:
336                 if( isNumberValue(value) )
337                 {
338                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
339                     RETURN_ON_EXCEPTION(this,ex);
340                     libvlc_audio_set_track(p_md, numberValue(value), &ex);
341                     RETURN_ON_EXCEPTION(this,ex);
342                     return INVOKERESULT_NO_ERROR;
343                 }
344                 return INVOKERESULT_INVALID_VALUE;
345             case ID_audio_channel:
346                 if( isNumberValue(value) )
347                 {
348                     libvlc_audio_set_channel(p_plugin->getVLC(),
349                                              numberValue(value), &ex);
350                     RETURN_ON_EXCEPTION(this,ex);
351                     return INVOKERESULT_NO_ERROR;
352                 }
353                 return INVOKERESULT_INVALID_VALUE;
354             default:
355                 ;
356         }
357     }
358     return INVOKERESULT_GENERIC_ERROR;
359 }
360
361 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
362 {
363     "toggleMute",
364     "description",
365 };
366 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
367
368 enum LibvlcAudioNPObjectMethodIds
369 {
370     ID_audio_togglemute,
371     ID_audio_description,
372 };
373
374 RuntimeNPObject::InvokeResult
375 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
376                             uint32_t argCount, NPVariant &result)
377 {
378     /* is plugin still running */
379     if( isPluginRunning() )
380     {
381         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
382         libvlc_exception_t ex;
383         libvlc_exception_init(&ex);
384
385         switch( index )
386         {
387             case ID_audio_togglemute:
388                 if( argCount == 0 )
389                 {
390                     libvlc_audio_toggle_mute(p_plugin->getVLC());
391                     VOID_TO_NPVARIANT(result);
392                     return INVOKERESULT_NO_ERROR;
393                 }
394                 return INVOKERESULT_NO_SUCH_METHOD;
395             case ID_audio_description:
396             {
397                 if( argCount == 1)
398                 {
399                     char *psz_name;
400                     int i_trackID, i_limit, i;
401                     libvlc_track_description_t *p_trackDesc;
402
403                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
404                     RETURN_ON_EXCEPTION(this,ex);
405
406                     /* get tracks description */
407                     p_trackDesc = libvlc_audio_get_track_description(p_md, &ex);
408                     RETURN_ON_EXCEPTION(this,ex);
409                     if( !p_trackDesc )
410                         return INVOKERESULT_GENERIC_ERROR;
411
412                     /* get the number of track available */
413                     i_limit = libvlc_audio_get_track_count(p_md, &ex);
414                     RETURN_ON_EXCEPTION(this,ex);
415
416                     /* check if a number is given by the user
417                      * and get the track number */
418                     if( isNumberValue(args[0]) )
419                         i_trackID = numberValue(args[0]);
420                     else
421                         return INVOKERESULT_INVALID_VALUE;
422
423                     /* if bad number is given return invalid value */
424                     if ( ( i_trackID > ( i_limit - 1 ) ) || ( i_trackID < 0 ) )
425                         return INVOKERESULT_INVALID_VALUE;
426
427                     /* get the good trackDesc */
428                     for( i = 0 ; i < i_trackID ; i++ )
429                     {
430                         p_trackDesc = p_trackDesc->p_next;
431                     }
432                     psz_name = p_trackDesc->psz_name;
433
434                     /* display the name of the track chosen */
435                     return invokeResultString( psz_name, result );
436                 }
437                 return INVOKERESULT_NO_SUCH_METHOD;
438             }
439             default:
440                 ;
441         }
442     }
443     return INVOKERESULT_GENERIC_ERROR;
444 }
445
446 /*
447 ** implementation of libvlc input object
448 */
449
450 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] =
451 {
452     "length",
453     "position",
454     "time",
455     "state",
456     "rate",
457     "fps",
458     "hasVout",
459 };
460 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
461
462 enum LibvlcInputNPObjectPropertyIds
463 {
464     ID_input_length,
465     ID_input_position,
466     ID_input_time,
467     ID_input_state,
468     ID_input_rate,
469     ID_input_fps,
470     ID_input_hasvout,
471 };
472
473 RuntimeNPObject::InvokeResult
474 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
475 {
476     /* is plugin still running */
477     if( isPluginRunning() )
478     {
479         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
480         libvlc_exception_t ex;
481         libvlc_exception_init(&ex);
482
483         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
484         if( libvlc_exception_raised(&ex) )
485         {
486             if( index != ID_input_state )
487             {
488                 NPN_SetException(this, libvlc_errmsg());
489                 libvlc_exception_clear(&ex);
490                 return INVOKERESULT_GENERIC_ERROR;
491             }
492             else
493             {
494                 /* for input state, return CLOSED rather than an exception */
495                 INT32_TO_NPVARIANT(0, result);
496                 libvlc_exception_clear(&ex);
497                 return INVOKERESULT_NO_ERROR;
498             }
499         }
500
501         switch( index )
502         {
503             case ID_input_length:
504             {
505                 double val = (double)libvlc_media_player_get_length(p_md, &ex);
506                 RETURN_ON_EXCEPTION(this,ex);
507                 DOUBLE_TO_NPVARIANT(val, result);
508                 return INVOKERESULT_NO_ERROR;
509             }
510             case ID_input_position:
511             {
512                 double val = libvlc_media_player_get_position(p_md, &ex);
513                 RETURN_ON_EXCEPTION(this,ex);
514                 DOUBLE_TO_NPVARIANT(val, result);
515                 return INVOKERESULT_NO_ERROR;
516             }
517             case ID_input_time:
518             {
519                 double val = (double)libvlc_media_player_get_time(p_md, &ex);
520                 RETURN_ON_EXCEPTION(this,ex);
521                 DOUBLE_TO_NPVARIANT(val, result);
522                 return INVOKERESULT_NO_ERROR;
523             }
524             case ID_input_state:
525             {
526                 int val = libvlc_media_player_get_state(p_md);
527                 RETURN_ON_EXCEPTION(this,ex);
528                 INT32_TO_NPVARIANT(val, result);
529                 return INVOKERESULT_NO_ERROR;
530             }
531             case ID_input_rate:
532             {
533                 float val = libvlc_media_player_get_rate(p_md, &ex);
534                 RETURN_ON_EXCEPTION(this,ex);
535                 DOUBLE_TO_NPVARIANT(val, result);
536                 return INVOKERESULT_NO_ERROR;
537             }
538             case ID_input_fps:
539             {
540                 double val = libvlc_media_player_get_fps(p_md, &ex);
541                 RETURN_ON_EXCEPTION(this,ex);
542                 DOUBLE_TO_NPVARIANT(val, result);
543                 return INVOKERESULT_NO_ERROR;
544             }
545             case ID_input_hasvout:
546             {
547                 bool val = p_plugin->player_has_vout(&ex);
548                 RETURN_ON_EXCEPTION(this,ex);
549                 BOOLEAN_TO_NPVARIANT(val, result);
550                 return INVOKERESULT_NO_ERROR;
551             }
552             default:
553                 ;
554         }
555     }
556     return INVOKERESULT_GENERIC_ERROR;
557 }
558
559 RuntimeNPObject::InvokeResult
560 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
561 {
562     /* is plugin still running */
563     if( isPluginRunning() )
564     {
565         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
566         libvlc_exception_t ex;
567         libvlc_exception_init(&ex);
568
569         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
570         RETURN_ON_EXCEPTION(this,ex);
571
572         switch( index )
573         {
574             case ID_input_position:
575             {
576                 if( ! NPVARIANT_IS_DOUBLE(value) )
577                 {
578                     return INVOKERESULT_INVALID_VALUE;
579                 }
580
581                 float val = (float)NPVARIANT_TO_DOUBLE(value);
582                 libvlc_media_player_set_position(p_md, val, &ex);
583                 RETURN_ON_EXCEPTION(this,ex);
584                 return INVOKERESULT_NO_ERROR;
585             }
586             case ID_input_time:
587             {
588                 int64_t val;
589                 if( NPVARIANT_IS_INT32(value) )
590                     val = (int64_t)NPVARIANT_TO_INT32(value);
591                 else if( NPVARIANT_IS_DOUBLE(value) )
592                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
593                 else
594                 {
595                     return INVOKERESULT_INVALID_VALUE;
596                 }
597
598                 libvlc_media_player_set_time(p_md, val, &ex);
599                 RETURN_ON_EXCEPTION(this,ex);
600                 return INVOKERESULT_NO_ERROR;
601             }
602             case ID_input_rate:
603             {
604                 float val;
605                 if( NPVARIANT_IS_INT32(value) )
606                     val = (float)NPVARIANT_TO_INT32(value);
607                 else if( NPVARIANT_IS_DOUBLE(value) )
608                     val = (float)NPVARIANT_TO_DOUBLE(value);
609                 else
610                 {
611                     return INVOKERESULT_INVALID_VALUE;
612                 }
613
614                 libvlc_media_player_set_rate(p_md, val, &ex);
615                 RETURN_ON_EXCEPTION(this,ex);
616                 return INVOKERESULT_NO_ERROR;
617             }
618             default:
619                 ;
620         }
621     }
622     return INVOKERESULT_GENERIC_ERROR;
623 }
624
625 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
626 {
627     /* no methods */
628     "none",
629 };
630 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
631
632 enum LibvlcInputNPObjectMethodIds
633 {
634     ID_none,
635 };
636
637 RuntimeNPObject::InvokeResult
638 LibvlcInputNPObject::invoke(int index, const NPVariant *args,
639                                     uint32_t argCount, NPVariant &result)
640 {
641     /* is plugin still running */
642     if( isPluginRunning() )
643     {
644         switch( index )
645         {
646             case ID_none:
647                 return INVOKERESULT_NO_SUCH_METHOD;
648             default:
649                 ;
650         }
651     }
652     return INVOKERESULT_GENERIC_ERROR;
653 }
654
655 /*
656 ** implementation of libvlc playlist items object
657 */
658
659 const NPUTF8 * const LibvlcPlaylistItemsNPObject::propertyNames[] =
660 {
661     "count",
662 };
663 COUNTNAMES(LibvlcPlaylistItemsNPObject,propertyCount,propertyNames);
664
665 enum LibvlcPlaylistItemsNPObjectPropertyIds
666 {
667     ID_playlistitems_count,
668 };
669
670 RuntimeNPObject::InvokeResult
671 LibvlcPlaylistItemsNPObject::getProperty(int index, NPVariant &result)
672 {
673     /* is plugin still running */
674     if( isPluginRunning() )
675     {
676         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
677
678         switch( index )
679         {
680             case ID_playlistitems_count:
681             {
682                 int val = p_plugin->playlist_count();
683                 INT32_TO_NPVARIANT(val, result);
684                 return INVOKERESULT_NO_ERROR;
685             }
686             default:
687                 ;
688         }
689     }
690     return INVOKERESULT_GENERIC_ERROR;
691 }
692
693 const NPUTF8 * const LibvlcPlaylistItemsNPObject::methodNames[] =
694 {
695     "clear",
696     "remove",
697 };
698 COUNTNAMES(LibvlcPlaylistItemsNPObject,methodCount,methodNames);
699
700 enum LibvlcPlaylistItemsNPObjectMethodIds
701 {
702     ID_playlistitems_clear,
703     ID_playlistitems_remove,
704 };
705
706 RuntimeNPObject::InvokeResult
707 LibvlcPlaylistItemsNPObject::invoke(int index, const NPVariant *args,
708                                     uint32_t argCount, NPVariant &result)
709 {
710     /* is plugin still running */
711     if( isPluginRunning() )
712     {
713         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
714         libvlc_exception_t ex;
715         libvlc_exception_init(&ex);
716
717         switch( index )
718         {
719             case ID_playlistitems_clear:
720                 if( argCount == 0 )
721                 {
722                     p_plugin->playlist_clear(&ex);
723                     RETURN_ON_EXCEPTION(this,ex);
724                     VOID_TO_NPVARIANT(result);
725                     return INVOKERESULT_NO_ERROR;
726                 }
727                 return INVOKERESULT_NO_SUCH_METHOD;
728             case ID_playlistitems_remove:
729                 if( (argCount == 1) && isNumberValue(args[0]) )
730                 {
731                     p_plugin->playlist_delete_item(numberValue(args[0]),&ex);
732                     RETURN_ON_EXCEPTION(this,ex);
733                     VOID_TO_NPVARIANT(result);
734                     return INVOKERESULT_NO_ERROR;
735                 }
736                 return INVOKERESULT_NO_SUCH_METHOD;
737             default:
738                 ;
739         }
740     }
741     return INVOKERESULT_GENERIC_ERROR;
742 }
743
744 /*
745 ** implementation of libvlc playlist object
746 */
747
748 LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()
749 {
750     // Why the isValid()?
751     if( isValid() && playlistItemsObj )
752         NPN_ReleaseObject(playlistItemsObj);
753 };
754
755 const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] =
756 {
757     "itemCount", /* deprecated */
758     "isPlaying",
759     "items",
760 };
761 COUNTNAMES(LibvlcPlaylistNPObject,propertyCount,propertyNames);
762
763 enum LibvlcPlaylistNPObjectPropertyIds
764 {
765     ID_playlist_itemcount,
766     ID_playlist_isplaying,
767     ID_playlist_items,
768 };
769
770 RuntimeNPObject::InvokeResult
771 LibvlcPlaylistNPObject::getProperty(int index, NPVariant &result)
772 {
773     /* is plugin still running */
774     if( isPluginRunning() )
775     {
776         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
777
778         switch( index )
779         {
780             case ID_playlist_itemcount: /* deprecated */
781             {
782                 int val = p_plugin->playlist_count();
783                 INT32_TO_NPVARIANT(val, result);
784                 return INVOKERESULT_NO_ERROR;
785             }
786             case ID_playlist_isplaying:
787             {
788                 int val = p_plugin->playlist_isplaying();
789                 BOOLEAN_TO_NPVARIANT(val, result);
790                 return INVOKERESULT_NO_ERROR;
791             }
792             case ID_playlist_items:
793             {
794                 InstantObj<LibvlcPlaylistItemsNPObject>( playlistItemsObj );
795                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
796                 return INVOKERESULT_NO_ERROR;
797             }
798             default:
799                 ;
800         }
801     }
802     return INVOKERESULT_GENERIC_ERROR;
803 }
804
805 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
806 {
807     "add",
808     "play",
809     "playItem",
810     "togglePause",
811     "stop",
812     "next",
813     "prev",
814     "clear", /* deprecated */
815     "removeItem", /* deprecated */
816 };
817 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
818
819 enum LibvlcPlaylistNPObjectMethodIds
820 {
821     ID_playlist_add,
822     ID_playlist_play,
823     ID_playlist_playItem,
824     ID_playlist_togglepause,
825     ID_playlist_stop,
826     ID_playlist_next,
827     ID_playlist_prev,
828     ID_playlist_clear,
829     ID_playlist_removeitem
830 };
831
832 RuntimeNPObject::InvokeResult
833 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
834                                uint32_t argCount, NPVariant &result)
835 {
836     /* is plugin still running */
837     if( isPluginRunning() )
838     {
839         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
840         libvlc_exception_t ex;
841         libvlc_exception_init(&ex);
842
843         switch( index )
844         {
845             // XXX FIXME this needs squashing into something much smaller
846             case ID_playlist_add:
847             {
848                 if( (argCount < 1) || (argCount > 3) )
849                     return INVOKERESULT_NO_SUCH_METHOD;
850                 if( !NPVARIANT_IS_STRING(args[0]) )
851                     return INVOKERESULT_NO_SUCH_METHOD;
852
853                 // grab URL
854                 if( NPVARIANT_IS_NULL(args[0]) )
855                     return INVOKERESULT_NO_SUCH_METHOD;
856
857                 char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
858                 if( !s )
859                     return INVOKERESULT_OUT_OF_MEMORY;
860
861                 char *url = p_plugin->getAbsoluteURL(s);
862                 if( url )
863                     free(s);
864                 else
865                     // problem with combining url, use argument
866                     url = s;
867
868                 char *name = NULL;
869
870                 // grab name if available
871                 if( argCount > 1 )
872                 {
873                     if( NPVARIANT_IS_NULL(args[1]) )
874                     {
875                         // do nothing
876                     }
877                     else if( NPVARIANT_IS_STRING(args[1]) )
878                     {
879                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
880                     }
881                     else
882                     {
883                         free(url);
884                         return INVOKERESULT_INVALID_VALUE;
885                     }
886                 }
887
888                 int i_options = 0;
889                 char** ppsz_options = NULL;
890
891                 // grab options if available
892                 if( argCount > 2 )
893                 {
894                     if( NPVARIANT_IS_NULL(args[2]) )
895                     {
896                         // do nothing
897                     }
898                     else if( NPVARIANT_IS_STRING(args[2]) )
899                     {
900                         parseOptions(NPVARIANT_TO_STRING(args[2]),
901                                      &i_options, &ppsz_options);
902
903                     }
904                     else if( NPVARIANT_IS_OBJECT(args[2]) )
905                     {
906                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
907                                      &i_options, &ppsz_options);
908                     }
909                     else
910                     {
911                         free(url);
912                         free(name);
913                         return INVOKERESULT_INVALID_VALUE;
914                     }
915                 }
916
917                 int item = p_plugin->playlist_add_extended_untrusted(url, name,
918                       i_options, const_cast<const char **>(ppsz_options), &ex);
919                 free(url);
920                 free(name);
921                 for( int i=0; i< i_options; ++i )
922                 {
923                     free(ppsz_options[i]);
924                 }
925                 free(ppsz_options);
926
927                 RETURN_ON_EXCEPTION(this,ex);
928                 INT32_TO_NPVARIANT(item, result);
929                 return INVOKERESULT_NO_ERROR;
930             }
931             case ID_playlist_play:
932                 if( argCount == 0 )
933                 {
934                     p_plugin->playlist_play(&ex);
935                     RETURN_ON_EXCEPTION(this,ex);
936                     VOID_TO_NPVARIANT(result);
937                     return INVOKERESULT_NO_ERROR;
938                 }
939                 return INVOKERESULT_NO_SUCH_METHOD;
940             case ID_playlist_playItem:
941                 if( (argCount == 1) && isNumberValue(args[0]) )
942                 {
943                     p_plugin->playlist_play_item(numberValue(args[0]),&ex);
944                     RETURN_ON_EXCEPTION(this,ex);
945                     VOID_TO_NPVARIANT(result);
946                     return INVOKERESULT_NO_ERROR;
947                 }
948                 return INVOKERESULT_NO_SUCH_METHOD;
949             case ID_playlist_togglepause:
950                 if( argCount == 0 )
951                 {
952                     p_plugin->playlist_pause(&ex);
953                     RETURN_ON_EXCEPTION(this,ex);
954                     VOID_TO_NPVARIANT(result);
955                     return INVOKERESULT_NO_ERROR;
956                 }
957                 return INVOKERESULT_NO_SUCH_METHOD;
958             case ID_playlist_stop:
959                 if( argCount == 0 )
960                 {
961                     p_plugin->playlist_stop();
962                     VOID_TO_NPVARIANT(result);
963                     return INVOKERESULT_NO_ERROR;
964                 }
965                 return INVOKERESULT_NO_SUCH_METHOD;
966             case ID_playlist_next:
967                 if( argCount == 0 )
968                 {
969                     p_plugin->playlist_next(&ex);
970                     RETURN_ON_EXCEPTION(this,ex);
971                     VOID_TO_NPVARIANT(result);
972                     return INVOKERESULT_NO_ERROR;
973                 }
974                 return INVOKERESULT_NO_SUCH_METHOD;
975             case ID_playlist_prev:
976                 if( argCount == 0 )
977                 {
978                     p_plugin->playlist_prev(&ex);
979                     RETURN_ON_EXCEPTION(this,ex);
980                     VOID_TO_NPVARIANT(result);
981                     return INVOKERESULT_NO_ERROR;
982                 }
983                 return INVOKERESULT_NO_SUCH_METHOD;
984             case ID_playlist_clear: /* deprecated */
985                 if( argCount == 0 )
986                 {
987                     p_plugin->playlist_clear(&ex);
988                     RETURN_ON_EXCEPTION(this,ex);
989                     VOID_TO_NPVARIANT(result);
990                     return INVOKERESULT_NO_ERROR;
991                 }
992                 return INVOKERESULT_NO_SUCH_METHOD;
993             case ID_playlist_removeitem: /* deprecated */
994                 if( (argCount == 1) && isNumberValue(args[0]) )
995                 {
996                     p_plugin->playlist_delete_item(numberValue(args[0]), &ex);
997                     RETURN_ON_EXCEPTION(this,ex);
998                     VOID_TO_NPVARIANT(result);
999                     return INVOKERESULT_NO_ERROR;
1000                 }
1001                 return INVOKERESULT_NO_SUCH_METHOD;
1002             default:
1003                 ;
1004         }
1005     }
1006     return INVOKERESULT_GENERIC_ERROR;
1007 }
1008
1009 // XXX FIXME The new playlist_add creates a media instance and feeds it
1010 // XXX FIXME these options one at a time, so this hunk of code does lots
1011 // XXX FIXME of unnecessairy work. Break out something that can do one
1012 // XXX FIXME option at a time and doesn't need to realloc().
1013 // XXX FIXME Same for the other version of parseOptions.
1014
1015 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
1016                                          int *i_options, char*** ppsz_options)
1017 {
1018     if( nps.utf8length )
1019     {
1020         char *s = stringValue(nps);
1021         char *val = s;
1022         if( val )
1023         {
1024             long capacity = 16;
1025             char **options = (char **)malloc(capacity*sizeof(char *));
1026             if( options )
1027             {
1028                 int nOptions = 0;
1029
1030                 char *end = val + nps.utf8length;
1031                 while( val < end )
1032                 {
1033                     // skip leading blanks
1034                     while( (val < end)
1035                         && ((*val == ' ' ) || (*val == '\t')) )
1036                         ++val;
1037
1038                     char *start = val;
1039                     // skip till we get a blank character
1040                     while( (val < end)
1041                         && (*val != ' ' )
1042                         && (*val != '\t') )
1043                     {
1044                         char c = *(val++);
1045                         if( ('\'' == c) || ('"' == c) )
1046                         {
1047                             // skip till end of string
1048                             while( (val < end) && (*(val++) != c ) );
1049                         }
1050                     }
1051
1052                     if( val > start )
1053                     {
1054                         if( nOptions == capacity )
1055                         {
1056                             capacity += 16;
1057                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1058                             if( ! moreOptions )
1059                             {
1060                                 /* failed to allocate more memory */
1061                                 free(s);
1062                                 /* return what we got so far */
1063                                 *i_options = nOptions;
1064                                 *ppsz_options = options;
1065                                 return;
1066                             }
1067                             options = moreOptions;
1068                         }
1069                         *(val++) = '\0';
1070                         options[nOptions++] = strdup(start);
1071                     }
1072                     else
1073                         // must be end of string
1074                         break;
1075                 }
1076                 *i_options = nOptions;
1077                 *ppsz_options = options;
1078             }
1079             free(s);
1080         }
1081     }
1082 }
1083
1084 // XXX FIXME See comment at the other parseOptions variant.
1085 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
1086                                           char*** ppsz_options)
1087 {
1088     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
1089
1090     NPVariant value;
1091
1092     /* we are expecting to have a Javascript Array object */
1093     NPIdentifier propId = NPN_GetStringIdentifier("length");
1094     if( NPN_GetProperty(_instance, obj, propId, &value) )
1095     {
1096         int count = numberValue(value);
1097         NPN_ReleaseVariantValue(&value);
1098
1099         if( count )
1100         {
1101             long capacity = 16;
1102             char **options = (char **)malloc(capacity*sizeof(char *));
1103             if( options )
1104             {
1105                 int nOptions = 0;
1106
1107                 while( nOptions < count )
1108                 {
1109                     propId = NPN_GetIntIdentifier(nOptions);
1110                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
1111                         /* return what we got so far */
1112                         break;
1113
1114                     if( ! NPVARIANT_IS_STRING(value) )
1115                     {
1116                         /* return what we got so far */
1117                         NPN_ReleaseVariantValue(&value);
1118                         break;
1119                     }
1120
1121                     if( nOptions == capacity )
1122                     {
1123                         capacity += 16;
1124                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1125                         if( ! moreOptions )
1126                         {
1127                             /* failed to allocate more memory */
1128                             NPN_ReleaseVariantValue(&value);
1129                             /* return what we got so far */
1130                             *i_options = nOptions;
1131                             *ppsz_options = options;
1132                             break;
1133                         }
1134                         options = moreOptions;
1135                     }
1136
1137                     options[nOptions++] = stringValue(value);
1138                     NPN_ReleaseVariantValue(&value);
1139                 }
1140                 *i_options = nOptions;
1141                 *ppsz_options = options;
1142             }
1143         }
1144     }
1145 }
1146
1147 /*
1148 ** implementation of libvlc subtitle object
1149 */
1150
1151 const NPUTF8 * const LibvlcSubtitleNPObject::propertyNames[] =
1152 {
1153     "track",
1154     "count",
1155 };
1156
1157 enum LibvlcSubtitleNPObjectPropertyIds
1158 {
1159     ID_subtitle_track,
1160     ID_subtitle_count,
1161 };
1162 COUNTNAMES(LibvlcSubtitleNPObject,propertyCount,propertyNames);
1163
1164 RuntimeNPObject::InvokeResult
1165 LibvlcSubtitleNPObject::getProperty(int index, NPVariant &result)
1166 {
1167     /* is plugin still running */
1168     if( isPluginRunning() )
1169     {
1170         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1171         libvlc_exception_t ex;
1172         libvlc_exception_init(&ex);
1173
1174         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1175         RETURN_ON_EXCEPTION(this,ex);
1176
1177         switch( index )
1178         {
1179             case ID_subtitle_track:
1180             {
1181                 /* get the current subtitle ID */
1182                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1183                 RETURN_ON_EXCEPTION(this,ex);
1184                 /* return it */
1185                 INT32_TO_NPVARIANT(i_spu, result);
1186                 return INVOKERESULT_NO_ERROR;
1187             }
1188             case ID_subtitle_count:
1189             {
1190                 /* get the number of subtitles available */
1191                 int i_spu = libvlc_video_get_spu_count(p_md, &ex);
1192                 RETURN_ON_EXCEPTION(this,ex);
1193                 /* return it */
1194                 INT32_TO_NPVARIANT(i_spu, result);
1195                 return INVOKERESULT_NO_ERROR;
1196             }
1197         }
1198     }
1199     return INVOKERESULT_GENERIC_ERROR;
1200 }
1201
1202 RuntimeNPObject::InvokeResult
1203 LibvlcSubtitleNPObject::setProperty(int index, const NPVariant &value)
1204 {
1205     /* is plugin still running */
1206     if( isPluginRunning() )
1207     {
1208         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1209         libvlc_exception_t ex;
1210         libvlc_exception_init(&ex);
1211
1212         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1213         RETURN_ON_EXCEPTION(this,ex);
1214
1215         switch( index )
1216         {
1217             case ID_subtitle_track:
1218             {
1219                 if( isNumberValue(value) )
1220                 {
1221                     /* set the new subtitle track to show */
1222                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1223                     RETURN_ON_EXCEPTION(this,ex);
1224
1225                     return INVOKERESULT_NO_ERROR;
1226                 }
1227                 return INVOKERESULT_INVALID_VALUE;
1228             }
1229         }
1230     }
1231     return INVOKERESULT_GENERIC_ERROR;
1232 }
1233
1234 const NPUTF8 * const LibvlcSubtitleNPObject::methodNames[] =
1235 {
1236     "description"
1237 };
1238 COUNTNAMES(LibvlcSubtitleNPObject,methodCount,methodNames);
1239
1240 enum LibvlcSubtitleNPObjectMethodIds
1241 {
1242     ID_subtitle_description
1243 };
1244
1245 RuntimeNPObject::InvokeResult
1246 LibvlcSubtitleNPObject::invoke(int index, const NPVariant *args,
1247                             uint32_t argCount, NPVariant &result)
1248 {
1249     /* is plugin still running */
1250     if( isPluginRunning() )
1251     {
1252         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1253         libvlc_exception_t ex;
1254         libvlc_exception_init(&ex);
1255
1256         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1257         RETURN_ON_EXCEPTION(this,ex);
1258
1259         switch( index )
1260         {
1261             case ID_subtitle_description:
1262             {
1263                 if( argCount == 1)
1264                 {
1265                     char *psz_name;
1266                     int i_spuID, i_limit, i;
1267                     libvlc_track_description_t *p_spuDesc;
1268
1269                     /* get subtitles description */
1270                     p_spuDesc = libvlc_video_get_spu_description(p_md, &ex);
1271                     RETURN_ON_EXCEPTION(this,ex);
1272                     if( !p_spuDesc )
1273                         return INVOKERESULT_GENERIC_ERROR;
1274
1275                     /* get the number of subtitle available */
1276                     i_limit = libvlc_video_get_spu_count(p_md, &ex);
1277                     RETURN_ON_EXCEPTION(this,ex);
1278
1279                     /* check if a number is given by the user
1280                      * and get the subtitle number */
1281                     if( isNumberValue(args[0]) )
1282                         i_spuID = numberValue(args[0]);
1283                     else
1284                         return INVOKERESULT_INVALID_VALUE;
1285
1286                     /* if bad number is given return invalid value */
1287                     if ( ( i_spuID > ( i_limit -1 ) ) || ( i_spuID < 0 ) )
1288                         return INVOKERESULT_INVALID_VALUE;
1289
1290                     /* get the good spuDesc */
1291                     for( i = 0 ; i < i_spuID ; i++ )
1292                     {
1293                         p_spuDesc = p_spuDesc->p_next;
1294                     }
1295                     psz_name = p_spuDesc->psz_name;
1296
1297                     /* return the name of the track chosen */
1298                     return invokeResultString(psz_name, result);
1299                 }
1300                 return INVOKERESULT_NO_SUCH_METHOD;
1301             }
1302             default:
1303                 return INVOKERESULT_NO_SUCH_METHOD;
1304         }
1305     }
1306     return INVOKERESULT_GENERIC_ERROR;
1307 }
1308
1309 /*
1310 ** implementation of libvlc video object
1311 */
1312
1313 LibvlcVideoNPObject::~LibvlcVideoNPObject()
1314 {
1315     if( isValid() )
1316     {
1317         if( marqueeObj ) NPN_ReleaseObject(marqueeObj);
1318         if( logoObj    ) NPN_ReleaseObject(logoObj);
1319         if( deintObj   ) NPN_ReleaseObject(deintObj);
1320     }
1321 }
1322
1323 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
1324 {
1325     "fullscreen",
1326     "height",
1327     "width",
1328     "aspectRatio",
1329     "subtitle",
1330     "crop",
1331     "teletext",
1332     "marquee",
1333     "logo",
1334     "deinterlace",
1335 };
1336
1337 enum LibvlcVideoNPObjectPropertyIds
1338 {
1339     ID_video_fullscreen,
1340     ID_video_height,
1341     ID_video_width,
1342     ID_video_aspectratio,
1343     ID_video_subtitle,
1344     ID_video_crop,
1345     ID_video_teletext,
1346     ID_video_marquee,
1347     ID_video_logo,
1348     ID_video_deinterlace,
1349 };
1350 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1351
1352 RuntimeNPObject::InvokeResult
1353 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1354 {
1355     /* is plugin still running */
1356     if( isPluginRunning() )
1357     {
1358         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1359         libvlc_exception_t ex;
1360         libvlc_exception_init(&ex);
1361
1362         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1363         RETURN_ON_EXCEPTION(this,ex);
1364
1365         switch( index )
1366         {
1367             case ID_video_fullscreen:
1368             {
1369                 int val = p_plugin->get_fullscreen(&ex);
1370                 RETURN_ON_EXCEPTION(this,ex);
1371                 BOOLEAN_TO_NPVARIANT(val, result);
1372                 return INVOKERESULT_NO_ERROR;
1373             }
1374             case ID_video_height:
1375             {
1376                 int val = libvlc_video_get_height(p_md, &ex);
1377                 RETURN_ON_EXCEPTION(this,ex);
1378                 INT32_TO_NPVARIANT(val, result);
1379                 return INVOKERESULT_NO_ERROR;
1380             }
1381             case ID_video_width:
1382             {
1383                 int val = libvlc_video_get_width(p_md, &ex);
1384                 RETURN_ON_EXCEPTION(this,ex);
1385                 INT32_TO_NPVARIANT(val, result);
1386                 return INVOKERESULT_NO_ERROR;
1387             }
1388             case ID_video_aspectratio:
1389             {
1390                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1391                 RETURN_ON_EXCEPTION(this,ex);
1392                 if( !psz_aspect )
1393                     return INVOKERESULT_GENERIC_ERROR;
1394
1395                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1396                 return INVOKERESULT_NO_ERROR;
1397             }
1398             case ID_video_subtitle:
1399             {
1400                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1401                 RETURN_ON_EXCEPTION(this,ex);
1402                 INT32_TO_NPVARIANT(i_spu, result);
1403                 return INVOKERESULT_NO_ERROR;
1404             }
1405             case ID_video_crop:
1406             {
1407                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1408                 RETURN_ON_EXCEPTION(this,ex);
1409                 if( !psz_geometry )
1410                     return INVOKERESULT_GENERIC_ERROR;
1411
1412                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1413                 return INVOKERESULT_NO_ERROR;
1414             }
1415             case ID_video_teletext:
1416             {
1417 /*                int i_page = libvlc_video_get_teletext(p_md, &ex);
1418                 RETURN_ON_EXCEPTION(this,ex);
1419                 INT32_TO_NPVARIANT(i_page, result);
1420                 return INVOKERESULT_NO_ERROR;
1421 */
1422                 return INVOKERESULT_NO_SUCH_METHOD;
1423             }
1424             case ID_video_marquee:
1425             {
1426                 InstantObj<LibvlcMarqueeNPObject>( marqueeObj );
1427                 OBJECT_TO_NPVARIANT(NPN_RetainObject(marqueeObj), result);
1428                 return INVOKERESULT_NO_ERROR;
1429             }
1430             case ID_video_logo:
1431             {
1432                 InstantObj<LibvlcLogoNPObject>( logoObj );
1433                 OBJECT_TO_NPVARIANT(NPN_RetainObject(logoObj), result);
1434                 return INVOKERESULT_NO_ERROR;
1435             }
1436             case ID_video_deinterlace:
1437             {
1438                 InstantObj<LibvlcDeinterlaceNPObject>( deintObj );
1439                 OBJECT_TO_NPVARIANT(NPN_RetainObject(deintObj), result);
1440                 return INVOKERESULT_NO_ERROR;
1441             }
1442         }
1443     }
1444     return INVOKERESULT_GENERIC_ERROR;
1445 }
1446
1447 RuntimeNPObject::InvokeResult
1448 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1449 {
1450     /* is plugin still running */
1451     if( isPluginRunning() )
1452     {
1453         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1454         libvlc_exception_t ex;
1455         libvlc_exception_init(&ex);
1456
1457         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1458         RETURN_ON_EXCEPTION(this,ex);
1459
1460         switch( index )
1461         {
1462             case ID_video_fullscreen:
1463             {
1464                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1465                 {
1466                     return INVOKERESULT_INVALID_VALUE;
1467                 }
1468
1469                 int val = NPVARIANT_TO_BOOLEAN(value);
1470                 p_plugin->set_fullscreen(val, &ex);
1471                 RETURN_ON_EXCEPTION(this,ex);
1472                 return INVOKERESULT_NO_ERROR;
1473             }
1474             case ID_video_aspectratio:
1475             {
1476                 char *psz_aspect = NULL;
1477
1478                 if( ! NPVARIANT_IS_STRING(value) )
1479                 {
1480                     return INVOKERESULT_INVALID_VALUE;
1481                 }
1482
1483                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1484                 if( !psz_aspect )
1485                 {
1486                     return INVOKERESULT_GENERIC_ERROR;
1487                 }
1488
1489                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1490                 free(psz_aspect);
1491                 RETURN_ON_EXCEPTION(this,ex);
1492
1493                 return INVOKERESULT_NO_ERROR;
1494             }
1495             case ID_video_subtitle:
1496             {
1497                 if( isNumberValue(value) )
1498                 {
1499                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1500                     RETURN_ON_EXCEPTION(this,ex);
1501
1502                     return INVOKERESULT_NO_ERROR;
1503                 }
1504                 return INVOKERESULT_INVALID_VALUE;
1505             }
1506             case ID_video_crop:
1507             {
1508                 char *psz_geometry = NULL;
1509
1510                 if( ! NPVARIANT_IS_STRING(value) )
1511                 {
1512                     return INVOKERESULT_INVALID_VALUE;
1513                 }
1514
1515                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1516                 if( !psz_geometry )
1517                 {
1518                     return INVOKERESULT_GENERIC_ERROR;
1519                 }
1520
1521                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1522                 free(psz_geometry);
1523                 RETURN_ON_EXCEPTION(this,ex);
1524
1525                 return INVOKERESULT_NO_ERROR;
1526             }
1527             case ID_video_teletext:
1528             {
1529                 if( isNumberValue(value) )
1530                 {
1531 /*
1532                     libvlc_video_set_teletext(p_md, numberValue(value), &ex);
1533                     RETURN_ON_EXCEPTION(this,ex);
1534
1535                     return INVOKERESULT_NO_ERROR;
1536 */
1537                     return INVOKERESULT_NO_SUCH_METHOD;
1538                 }
1539                 return INVOKERESULT_INVALID_VALUE;
1540             }
1541         }
1542     }
1543     return INVOKERESULT_GENERIC_ERROR;
1544 }
1545
1546 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1547 {
1548     "toggleFullscreen",
1549     "toggleTeletext",
1550 };
1551 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1552
1553 enum LibvlcVideoNPObjectMethodIds
1554 {
1555     ID_video_togglefullscreen,
1556     ID_video_toggleteletext,
1557 };
1558
1559 RuntimeNPObject::InvokeResult
1560 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1561                             uint32_t argCount, NPVariant &result)
1562 {
1563     /* is plugin still running */
1564     if( isPluginRunning() )
1565     {
1566         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1567         libvlc_exception_t ex;
1568         libvlc_exception_init(&ex);
1569
1570         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1571         RETURN_ON_EXCEPTION(this,ex);
1572
1573         switch( index )
1574         {
1575             case ID_video_togglefullscreen:
1576             {
1577                 if( argCount == 0 )
1578                 {
1579                     p_plugin->toggle_fullscreen(&ex);
1580                     RETURN_ON_EXCEPTION(this,ex);
1581                     VOID_TO_NPVARIANT(result);
1582                     return INVOKERESULT_NO_ERROR;
1583                 }
1584                 return INVOKERESULT_NO_SUCH_METHOD;
1585             }
1586             case ID_video_toggleteletext:
1587             {
1588                 if( argCount == 0 )
1589                 {
1590                     libvlc_toggle_teletext(p_md, &ex);
1591                     RETURN_ON_EXCEPTION(this,ex);
1592                     VOID_TO_NPVARIANT(result);
1593                     return INVOKERESULT_NO_ERROR;
1594                 }
1595                 return INVOKERESULT_NO_SUCH_METHOD;
1596             }
1597             default:
1598                 return INVOKERESULT_NO_SUCH_METHOD;
1599         }
1600     }
1601     return INVOKERESULT_GENERIC_ERROR;
1602 }
1603
1604 /*
1605 ** implementation of libvlc marquee object
1606 */
1607
1608 const NPUTF8 * const LibvlcMarqueeNPObject::propertyNames[] =
1609 {
1610     "color",
1611     "opacity",
1612     "position",
1613     "refresh",
1614     "size",
1615     "text",
1616     "timeout",
1617     "x",
1618     "y",
1619 };
1620
1621 enum LibvlcMarqueeNPObjectPropertyIds
1622 {
1623     ID_marquee_color,
1624     ID_marquee_opacity,
1625     ID_marquee_position,
1626     ID_marquee_refresh,
1627     ID_marquee_size,
1628     ID_marquee_text,
1629     ID_marquee_timeout,
1630     ID_marquee_x,
1631     ID_marquee_y,
1632 };
1633
1634 COUNTNAMES(LibvlcMarqueeNPObject,propertyCount,propertyNames);
1635
1636 static const unsigned char marquee_idx[] = {
1637     libvlc_marquee_Color,
1638     libvlc_marquee_Opacity,
1639     libvlc_marquee_Position,
1640     libvlc_marquee_Refresh,
1641     libvlc_marquee_Size,
1642     0,
1643     libvlc_marquee_Timeout,
1644     libvlc_marquee_X,
1645     libvlc_marquee_Y,
1646 };
1647
1648 RuntimeNPObject::InvokeResult
1649 LibvlcMarqueeNPObject::getProperty(int index, NPVariant &result)
1650 {
1651     char *psz;
1652
1653     if( !isPluginRunning() )
1654         return INVOKERESULT_GENERIC_ERROR;
1655
1656     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1657     libvlc_exception_t ex;
1658     libvlc_exception_init(&ex);
1659
1660     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1661     RETURN_ON_EXCEPTION(this,ex);
1662
1663     switch( index )
1664     {
1665     case ID_marquee_color:
1666     case ID_marquee_opacity:
1667     case ID_marquee_refresh:
1668     case ID_marquee_timeout:
1669     case ID_marquee_size:
1670     case ID_marquee_x:
1671     case ID_marquee_y:
1672         INT32_TO_NPVARIANT(
1673             libvlc_video_get_marquee_int(p_md, marquee_idx[index], &ex),
1674             result );
1675         RETURN_ON_EXCEPTION(this,ex);
1676         return INVOKERESULT_NO_ERROR;
1677
1678     case ID_marquee_position:
1679         STRINGZ_TO_NPVARIANT( position_bynumber(
1680             libvlc_video_get_marquee_int(p_md, libvlc_marquee_Position, &ex) ),
1681             result );
1682
1683         RETURN_ON_EXCEPTION(this,ex);
1684         break;
1685
1686     case ID_marquee_text:
1687         psz = libvlc_video_get_marquee_string(p_md, libvlc_marquee_Text, &ex);
1688         if( psz )
1689         {
1690             STRINGZ_TO_NPVARIANT(psz, result);
1691             return INVOKERESULT_NO_ERROR;
1692         }
1693         break;
1694     }
1695     return INVOKERESULT_GENERIC_ERROR;
1696 }
1697
1698 RuntimeNPObject::InvokeResult
1699 LibvlcMarqueeNPObject::setProperty(int index, const NPVariant &value)
1700 {
1701     size_t i;
1702
1703     if( !isPluginRunning() )
1704         return INVOKERESULT_GENERIC_ERROR;
1705
1706     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1707     libvlc_exception_t ex;
1708     libvlc_exception_init(&ex);
1709     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1710     RETURN_ON_EXCEPTION(this,ex);
1711
1712     switch( index )
1713     {
1714     case ID_marquee_color:
1715     case ID_marquee_opacity:
1716     case ID_marquee_refresh:
1717     case ID_marquee_timeout:
1718     case ID_marquee_x:
1719     case ID_marquee_y:
1720         if( NPVARIANT_IS_INT32( value ) )
1721         {
1722             libvlc_video_set_marquee_int(p_md, marquee_idx[index],
1723                                          NPVARIANT_TO_INT32( value ), &ex);
1724             RETURN_ON_EXCEPTION(this,ex);
1725             return INVOKERESULT_NO_ERROR;
1726         }
1727         break;
1728
1729     case ID_marquee_position:
1730         if( !NPVARIANT_IS_STRING(value) ||
1731             !position_byname( NPVARIANT_TO_STRING(value).utf8characters, i ) )
1732             return INVOKERESULT_INVALID_VALUE;
1733
1734         libvlc_video_set_marquee_int(p_md, libvlc_marquee_Position, i, &ex);
1735         RETURN_ON_EXCEPTION(this,ex);
1736         return INVOKERESULT_NO_ERROR;
1737
1738     case ID_marquee_text:
1739         if( NPVARIANT_IS_STRING( value ) )
1740         {
1741             char *psz_text = stringValue( NPVARIANT_TO_STRING( value ) );
1742             libvlc_video_set_marquee_string(p_md, libvlc_marquee_Text,
1743                                             psz_text, &ex);
1744             free(psz_text);
1745             RETURN_ON_EXCEPTION(this,ex);
1746             return INVOKERESULT_NO_ERROR;
1747         }
1748         break;
1749     }
1750     return INVOKERESULT_NO_SUCH_METHOD;
1751 }
1752
1753 const NPUTF8 * const LibvlcMarqueeNPObject::methodNames[] =
1754 {
1755     "enable",
1756     "disable",
1757 };
1758 COUNTNAMES(LibvlcMarqueeNPObject,methodCount,methodNames);
1759
1760 enum LibvlcMarqueeNPObjectMethodIds
1761 {
1762     ID_marquee_enable,
1763     ID_marquee_disable,
1764 };
1765
1766 RuntimeNPObject::InvokeResult
1767 LibvlcMarqueeNPObject::invoke(int index, const NPVariant *args,
1768                             uint32_t argCount, NPVariant &result)
1769 {
1770     if( !isPluginRunning() )
1771         return INVOKERESULT_GENERIC_ERROR;
1772
1773     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1774     libvlc_exception_t ex;
1775     libvlc_exception_init(&ex);
1776
1777     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1778     RETURN_ON_EXCEPTION(this,ex);
1779
1780     switch( index )
1781     {
1782     case ID_marquee_enable:
1783     case ID_marquee_disable:
1784         libvlc_video_set_marquee_int(p_md, libvlc_marquee_Enable,
1785                                      index!=ID_marquee_disable, &ex);
1786         RETURN_ON_EXCEPTION(this,ex);
1787         VOID_TO_NPVARIANT(result);
1788         return INVOKERESULT_NO_ERROR;
1789     }
1790     return INVOKERESULT_NO_SUCH_METHOD;
1791 }
1792
1793 const NPUTF8 * const LibvlcLogoNPObject::propertyNames[] = {
1794     "delay",
1795     "repeat",
1796     "opacity",
1797     "position",
1798     "x",
1799     "y",
1800 };
1801 enum LibvlcLogoNPObjectPropertyIds {
1802     ID_logo_delay,
1803     ID_logo_repeat,
1804     ID_logo_opacity,
1805     ID_logo_position,
1806     ID_logo_x,
1807     ID_logo_y,
1808 };
1809 COUNTNAMES(LibvlcLogoNPObject,propertyCount,propertyNames);
1810 static const unsigned char logo_idx[] = {
1811     libvlc_logo_delay,
1812     libvlc_logo_repeat,
1813     libvlc_logo_opacity,
1814     0,
1815     libvlc_logo_x,
1816     libvlc_logo_y,
1817 };
1818
1819 RuntimeNPObject::InvokeResult
1820 LibvlcLogoNPObject::getProperty(int index, NPVariant &result)
1821 {
1822     if( !isPluginRunning() )
1823         return INVOKERESULT_GENERIC_ERROR;
1824
1825     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1826     libvlc_exception_t ex;
1827     libvlc_exception_init(&ex);
1828     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1829     RETURN_ON_EXCEPTION(this,ex);
1830
1831     switch( index )
1832     {
1833     case ID_logo_delay:
1834     case ID_logo_repeat:
1835     case ID_logo_opacity:
1836     case ID_logo_x:
1837     case ID_logo_y:
1838
1839         INT32_TO_NPVARIANT(
1840             libvlc_video_get_logo_int(p_md, logo_idx[index], &ex), result);
1841
1842         RETURN_ON_EXCEPTION(this,ex);
1843         break;
1844
1845     case ID_logo_position:
1846         STRINGZ_TO_NPVARIANT( position_bynumber(
1847             libvlc_video_get_logo_int(p_md, libvlc_logo_position, &ex) ),
1848             result );
1849
1850         RETURN_ON_EXCEPTION(this,ex);
1851         break;
1852     default:
1853         return INVOKERESULT_GENERIC_ERROR;
1854     }
1855     return INVOKERESULT_NO_ERROR;
1856 }
1857
1858 RuntimeNPObject::InvokeResult
1859 LibvlcLogoNPObject::setProperty(int index, const NPVariant &value)
1860 {
1861     size_t i;
1862
1863     if( !isPluginRunning() )
1864         return INVOKERESULT_GENERIC_ERROR;
1865
1866     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1867     libvlc_exception_t ex;
1868     libvlc_exception_init(&ex);
1869
1870     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1871     RETURN_ON_EXCEPTION(this,ex);
1872
1873     switch( index )
1874     {
1875     case ID_logo_delay:
1876     case ID_logo_repeat:
1877     case ID_logo_opacity:
1878     case ID_logo_x:
1879     case ID_logo_y:
1880         if( !NPVARIANT_IS_INT32(value) )
1881             return INVOKERESULT_INVALID_VALUE;
1882
1883         libvlc_video_set_logo_int(p_md, logo_idx[index],
1884                                   NPVARIANT_TO_INT32( value ), &ex);
1885
1886         RETURN_ON_EXCEPTION(this,ex);
1887         break;
1888
1889     case ID_logo_position:
1890         if( !NPVARIANT_IS_STRING(value) ||
1891             !position_byname( NPVARIANT_TO_STRING(value).utf8characters, i ) )
1892             return INVOKERESULT_INVALID_VALUE;
1893
1894         libvlc_video_set_logo_int(p_md, libvlc_logo_position, i, &ex);
1895
1896         RETURN_ON_EXCEPTION(this,ex);
1897         break;
1898     default:
1899         return INVOKERESULT_GENERIC_ERROR;
1900     }
1901     return INVOKERESULT_NO_ERROR;
1902 }
1903
1904
1905 const NPUTF8 * const LibvlcLogoNPObject::methodNames[] = {
1906     "enable",
1907     "disable",
1908     "file",
1909 };
1910 enum LibvlcLogoNPObjectMethodIds {
1911     ID_logo_enable,
1912     ID_logo_disable,
1913     ID_logo_file,
1914 };
1915 COUNTNAMES(LibvlcLogoNPObject,methodCount,methodNames);
1916
1917 RuntimeNPObject::InvokeResult
1918 LibvlcLogoNPObject::invoke(int index, const NPVariant *args,
1919                            uint32_t argCount, NPVariant &result)
1920 {
1921     char *buf, *h;
1922     size_t i, len;
1923
1924     if( !isPluginRunning() )
1925         return INVOKERESULT_GENERIC_ERROR;
1926
1927     libvlc_exception_t ex;
1928     libvlc_exception_init(&ex);
1929     libvlc_media_player_t *p_md = getPrivate<VlcPlugin>()->getMD(&ex);
1930     RETURN_ON_EXCEPTION(this,ex);
1931
1932     switch( index )
1933     {
1934     case ID_logo_enable:
1935     case ID_logo_disable:
1936         if( argCount != 0 )
1937             return INVOKERESULT_GENERIC_ERROR;
1938
1939         libvlc_video_set_logo_int(p_md, libvlc_logo_enable,
1940                                   index != ID_logo_disable, &ex);
1941         RETURN_ON_EXCEPTION(this,ex);
1942         VOID_TO_NPVARIANT(result);
1943         break;
1944
1945     case ID_logo_file:
1946         if( argCount == 0 )
1947             return INVOKERESULT_GENERIC_ERROR;
1948
1949         for( len=0,i=0;i<argCount;++i )
1950         {
1951             if( !NPVARIANT_IS_STRING(args[i]) )
1952                 return INVOKERESULT_INVALID_VALUE;
1953             len+=NPVARIANT_TO_STRING(args[i]).utf8length+1;
1954         }
1955
1956         buf = (char *)malloc( len+1 );
1957         if( !buf )
1958             return INVOKERESULT_OUT_OF_MEMORY;
1959
1960         for( h=buf,i=0;i<argCount;++i )
1961         {
1962             if(i) *h++=';';
1963             len=NPVARIANT_TO_STRING(args[i]).utf8length;
1964             memcpy(h,NPVARIANT_TO_STRING(args[i]).utf8characters,len);
1965             h+=len;
1966         }
1967         *h='\0';
1968
1969         libvlc_video_set_logo_string(p_md, libvlc_logo_file, buf, &ex);
1970         free( buf );
1971         RETURN_ON_EXCEPTION(this,ex);
1972         VOID_TO_NPVARIANT(result);
1973         break;
1974     default:
1975         return INVOKERESULT_NO_SUCH_METHOD;
1976     }
1977     return INVOKERESULT_NO_ERROR;
1978 }
1979
1980
1981 const NPUTF8 * const LibvlcDeinterlaceNPObject::propertyNames[] = {
1982 };
1983 enum LibvlcDeinterlaceNPObjectPropertyIds {
1984 };
1985 COUNTNAMES(LibvlcDeinterlaceNPObject,propertyCount,propertyNames);
1986
1987 RuntimeNPObject::InvokeResult
1988 LibvlcDeinterlaceNPObject::getProperty(int index, NPVariant &result)
1989 {
1990     return INVOKERESULT_GENERIC_ERROR;
1991 }
1992
1993 RuntimeNPObject::InvokeResult
1994 LibvlcDeinterlaceNPObject::setProperty(int index, const NPVariant &value)
1995 {
1996     return INVOKERESULT_GENERIC_ERROR;
1997 }
1998
1999
2000 const NPUTF8 * const LibvlcDeinterlaceNPObject::methodNames[] = {
2001     "enable",
2002     "disable",
2003 };
2004 enum LibvlcDeinterlaceNPObjectMethodIds {
2005     ID_deint_enable,
2006     ID_deint_disable,
2007 };
2008 COUNTNAMES(LibvlcDeinterlaceNPObject,methodCount,methodNames);
2009
2010 RuntimeNPObject::InvokeResult
2011 LibvlcDeinterlaceNPObject::invoke(int index, const NPVariant *args,
2012                            uint32_t argCount, NPVariant &result)
2013 {
2014     char *psz;
2015
2016     if( !isPluginRunning() )
2017         return INVOKERESULT_GENERIC_ERROR;
2018
2019     libvlc_exception_t ex;
2020     libvlc_exception_init(&ex);
2021     libvlc_media_player_t *p_md = getPrivate<VlcPlugin>()->getMD(&ex);
2022     RETURN_ON_EXCEPTION(this,ex);
2023
2024     switch( index )
2025     {
2026     case ID_deint_disable:
2027         libvlc_video_set_deinterlace(p_md, 0, "", &ex);
2028         RETURN_ON_EXCEPTION(this,ex);
2029         break;
2030
2031     case ID_deint_enable:
2032         if( argCount != 1 || !NPVARIANT_IS_STRING( args[0] ) )
2033             return INVOKERESULT_INVALID_VALUE;
2034
2035         psz = stringValue( NPVARIANT_TO_STRING( args[0] ) );
2036         libvlc_video_set_deinterlace(p_md, 1, psz, &ex);
2037         free(psz);
2038         RETURN_ON_EXCEPTION(this,ex);
2039         break;
2040
2041     default:
2042         return INVOKERESULT_NO_SUCH_METHOD;
2043     }
2044     return INVOKERESULT_NO_ERROR;
2045 }
2046