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