]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
macosx: fixed menubar appearance in fullscreen mode by partially reverting [46c93c9cc...
[vlc] / projects / mozilla / control / npolibvlc.cpp
1 /*****************************************************************************
2  * npolibvlc.cpp: official Javascript APIs
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *          Jan Paul Dinger <jpd@m2x.nl>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 /* Mozilla stuff */
31 #ifdef HAVE_MOZILLA_CONFIG_H
32 #   include <mozilla-config.h>
33 #endif
34
35 #include "vlcplugin.h"
36 #include "npolibvlc.h"
37
38 /*
39 ** Local helper macros and function
40 */
41 #define COUNTNAMES(a,b,c) const int a::b = sizeof(a::c)/sizeof(NPUTF8 *)
42 #define RETURN_ON_EXCEPTION(this,ex) \
43     do { if( libvlc_exception_raised(&ex) ) \
44     { \
45         NPN_SetException(this, libvlc_exception_get_message(&ex)); \
46         libvlc_exception_clear(&ex); \
47         return INVOKERESULT_GENERIC_ERROR; \
48     } } while(false)
49
50 /*
51 ** implementation of libvlc root object
52 */
53
54 LibvlcRootNPObject::~LibvlcRootNPObject()
55 {
56     /*
57     ** When the plugin is destroyed, firefox takes it upon itself to
58     ** destroy all 'live' script objects and ignores refcounting.
59     ** Therefore we cannot safely assume that refcounting will control
60     ** lifespan of objects. Hence they are only lazily created on
61     ** request, so that firefox can take ownership, and are not released
62     ** when the plugin is destroyed.
63     */
64     if( isValid() )
65     {
66         if( audioObj    ) NPN_ReleaseObject(audioObj);
67         if( inputObj    ) NPN_ReleaseObject(inputObj);
68         if( playlistObj ) NPN_ReleaseObject(playlistObj);
69         if( videoObj    ) NPN_ReleaseObject(videoObj);
70     }
71 }
72
73 const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
74 {
75     "audio",
76     "input",
77     "playlist",
78     "video",
79     "VersionInfo",
80 };
81 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
82
83 enum LibvlcRootNPObjectPropertyIds
84 {
85     ID_root_audio = 0,
86     ID_root_input,
87     ID_root_playlist,
88     ID_root_video,
89     ID_root_VersionInfo,
90 };
91
92 RuntimeNPObject::InvokeResult
93 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
94 {
95     /* is plugin still running */
96     if( isPluginRunning() )
97     {
98         switch( index )
99         {
100             case ID_root_audio:
101                 // create child object in lazyman fashion to avoid
102                 // ownership problem with firefox
103                 if( ! audioObj )
104                     audioObj = NPN_CreateObject(_instance,
105                              RuntimeNPClass<LibvlcAudioNPObject>::getClass());
106                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
107                 return INVOKERESULT_NO_ERROR;
108             case ID_root_input:
109                 // create child object in lazyman fashion to avoid
110                 // ownership problem with firefox
111                 if( ! inputObj )
112                     inputObj = NPN_CreateObject(_instance,
113                              RuntimeNPClass<LibvlcInputNPObject>::getClass());
114                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
115                 return INVOKERESULT_NO_ERROR;
116             case ID_root_playlist:
117                 // create child object in lazyman fashion to avoid
118                 // ownership problem with firefox
119                 if( ! playlistObj )
120                     playlistObj = NPN_CreateObject(_instance,
121                           RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());
122                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
123                 return INVOKERESULT_NO_ERROR;
124             case ID_root_video:
125                 // create child object in lazyman fashion to avoid
126                 // ownership problem with firefox
127                 if( ! videoObj )
128                     videoObj = NPN_CreateObject(_instance,
129                              RuntimeNPClass<LibvlcVideoNPObject>::getClass());
130                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
131                 return INVOKERESULT_NO_ERROR;
132             case ID_root_VersionInfo:
133             {
134                 const char *s = libvlc_get_version();
135                 int len = strlen(s);
136                 NPUTF8 *retval =(NPUTF8*)NPN_MemAlloc(len);
137                 if( !retval )
138                     return INVOKERESULT_OUT_OF_MEMORY;
139
140                 memcpy(retval, s, len);
141                 STRINGN_TO_NPVARIANT(retval, len, result);
142                 return INVOKERESULT_NO_ERROR;
143             }
144             default:
145                 ;
146         }
147     }
148     return INVOKERESULT_GENERIC_ERROR;
149 }
150
151 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
152 {
153     "versionInfo",
154 };
155 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
156
157 enum LibvlcRootNPObjectMethodIds
158 {
159     ID_root_versionInfo,
160 };
161
162 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
163                   const NPVariant *args, uint32_t argCount, NPVariant &result)
164 {
165     /* is plugin still running */
166     if( isPluginRunning() )
167     {
168         libvlc_exception_t ex;
169         libvlc_exception_init(&ex);
170
171         switch( index )
172         {
173             case ID_root_versionInfo:
174                 if( argCount == 0 )
175                 {
176                     const char *s = libvlc_get_version();
177                     int len = strlen(s);
178                     NPUTF8 *retval =(NPUTF8*)NPN_MemAlloc(len);
179                     if( !retval )
180                         return INVOKERESULT_OUT_OF_MEMORY;
181                     memcpy(retval, s, len);
182                     STRINGN_TO_NPVARIANT(retval, len, result);
183                     return INVOKERESULT_NO_ERROR;
184                 }
185                 return INVOKERESULT_NO_SUCH_METHOD;
186             default:
187                 ;
188         }
189     }
190     return INVOKERESULT_GENERIC_ERROR;
191 }
192
193 /*
194 ** implementation of libvlc audio object
195 */
196
197 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
198 {
199     "mute",
200     "volume",
201     "track",
202     "channel",
203 };
204 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
205
206 enum LibvlcAudioNPObjectPropertyIds
207 {
208     ID_audio_mute,
209     ID_audio_volume,
210     ID_audio_track,
211     ID_audio_channel,
212 };
213
214 RuntimeNPObject::InvokeResult
215 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
216 {
217     /* is plugin still running */
218     if( isPluginRunning() )
219     {
220         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
221         libvlc_exception_t ex;
222         libvlc_exception_init(&ex);
223
224         switch( index )
225         {
226             case ID_audio_mute:
227             {
228                 bool muted = libvlc_audio_get_mute(p_plugin->getVLC(), &ex);
229                 RETURN_ON_EXCEPTION(this,ex);
230                 BOOLEAN_TO_NPVARIANT(muted, result);
231                 return INVOKERESULT_NO_ERROR;
232             }
233             case ID_audio_volume:
234             {
235                 int volume = libvlc_audio_get_volume(p_plugin->getVLC(), &ex);
236                 RETURN_ON_EXCEPTION(this,ex);
237                 INT32_TO_NPVARIANT(volume, result);
238                 return INVOKERESULT_NO_ERROR;
239             }
240             case ID_audio_track:
241             {
242                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
243                 RETURN_ON_EXCEPTION(this,ex);
244                 int track = libvlc_audio_get_track(p_md, &ex);
245                 RETURN_ON_EXCEPTION(this,ex);
246                 INT32_TO_NPVARIANT(track, result);
247                 return INVOKERESULT_NO_ERROR;
248             }
249             case ID_audio_channel:
250             {
251                 int channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
252                 RETURN_ON_EXCEPTION(this,ex);
253                 INT32_TO_NPVARIANT(channel, result);
254                 return INVOKERESULT_NO_ERROR;
255             }
256             default:
257                 ;
258         }
259     }
260     return INVOKERESULT_GENERIC_ERROR;
261 }
262
263 RuntimeNPObject::InvokeResult
264 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
265 {
266     /* is plugin still running */
267     if( isPluginRunning() )
268     {
269         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
270         libvlc_exception_t ex;
271         libvlc_exception_init(&ex);
272
273         switch( index )
274         {
275             case ID_audio_mute:
276                 if( NPVARIANT_IS_BOOLEAN(value) )
277                 {
278                     libvlc_audio_set_mute(p_plugin->getVLC(),
279                                           NPVARIANT_TO_BOOLEAN(value), &ex);
280                     RETURN_ON_EXCEPTION(this,ex);
281                     return INVOKERESULT_NO_ERROR;
282                 }
283                 return INVOKERESULT_INVALID_VALUE;
284             case ID_audio_volume:
285                 if( isNumberValue(value) )
286                 {
287                     libvlc_audio_set_volume(p_plugin->getVLC(),
288                                             numberValue(value), &ex);
289                     RETURN_ON_EXCEPTION(this,ex);
290                     return INVOKERESULT_NO_ERROR;
291                 }
292                 return INVOKERESULT_INVALID_VALUE;
293             case ID_audio_track:
294                 if( isNumberValue(value) )
295                 {
296                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
297                     RETURN_ON_EXCEPTION(this,ex);
298                     libvlc_audio_set_track(p_md, numberValue(value), &ex);
299                     RETURN_ON_EXCEPTION(this,ex);
300                     return INVOKERESULT_NO_ERROR;
301                 }
302                 return INVOKERESULT_INVALID_VALUE;
303             case ID_audio_channel:
304                 if( isNumberValue(value) )
305                 {
306                     libvlc_audio_set_channel(p_plugin->getVLC(),
307                                              numberValue(value), &ex);
308                     RETURN_ON_EXCEPTION(this,ex);
309                     return INVOKERESULT_NO_ERROR;
310                 }
311                 return INVOKERESULT_INVALID_VALUE;
312             default:
313                 ;
314         }
315     }
316     return INVOKERESULT_GENERIC_ERROR;
317 }
318
319 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
320 {
321     "toggleMute",
322 };
323 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
324
325 enum LibvlcAudioNPObjectMethodIds
326 {
327     ID_audio_togglemute,
328 };
329
330 RuntimeNPObject::InvokeResult
331 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
332                             uint32_t argCount, NPVariant &result)
333 {
334     /* is plugin still running */
335     if( isPluginRunning() )
336     {
337         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
338         libvlc_exception_t ex;
339         libvlc_exception_init(&ex);
340
341         switch( index )
342         {
343             case ID_audio_togglemute:
344                 if( argCount == 0 )
345                 {
346                     libvlc_audio_toggle_mute(p_plugin->getVLC(), &ex);
347                     RETURN_ON_EXCEPTION(this,ex);
348                     VOID_TO_NPVARIANT(result);
349                     return INVOKERESULT_NO_ERROR;
350                 }
351                 return INVOKERESULT_NO_SUCH_METHOD;
352             default:
353                 ;
354         }
355     }
356     return INVOKERESULT_GENERIC_ERROR;
357 }
358
359 /*
360 ** implementation of libvlc input object
361 */
362
363 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] =
364 {
365     "length",
366     "position",
367     "time",
368     "state",
369     "rate",
370     "fps",
371     "hasVout",
372 };
373 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
374
375 enum LibvlcInputNPObjectPropertyIds
376 {
377     ID_input_length,
378     ID_input_position,
379     ID_input_time,
380     ID_input_state,
381     ID_input_rate,
382     ID_input_fps,
383     ID_input_hasvout,
384 };
385
386 RuntimeNPObject::InvokeResult
387 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
388 {
389     /* is plugin still running */
390     if( isPluginRunning() )
391     {
392         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
393         libvlc_exception_t ex;
394         libvlc_exception_init(&ex);
395
396         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
397         if( libvlc_exception_raised(&ex) )
398         {
399             if( index != ID_input_state )
400             {
401                 NPN_SetException(this, libvlc_exception_get_message(&ex));
402                 libvlc_exception_clear(&ex);
403                 return INVOKERESULT_GENERIC_ERROR;
404             }
405             else
406             {
407                 /* for input state, return CLOSED rather than an exception */
408                 INT32_TO_NPVARIANT(0, result);
409                 libvlc_exception_clear(&ex);
410                 return INVOKERESULT_NO_ERROR;
411             }
412         }
413
414         switch( index )
415         {
416             case ID_input_length:
417             {
418                 double val = (double)libvlc_media_player_get_length(p_md, &ex);
419                 RETURN_ON_EXCEPTION(this,ex);
420                 DOUBLE_TO_NPVARIANT(val, result);
421                 return INVOKERESULT_NO_ERROR;
422             }
423             case ID_input_position:
424             {
425                 double val = libvlc_media_player_get_position(p_md, &ex);
426                 RETURN_ON_EXCEPTION(this,ex);
427                 DOUBLE_TO_NPVARIANT(val, result);
428                 return INVOKERESULT_NO_ERROR;
429             }
430             case ID_input_time:
431             {
432                 double val = (double)libvlc_media_player_get_time(p_md, &ex);
433                 RETURN_ON_EXCEPTION(this,ex);
434                 DOUBLE_TO_NPVARIANT(val, result);
435                 return INVOKERESULT_NO_ERROR;
436             }
437             case ID_input_state:
438             {
439                 int val = libvlc_media_player_get_state(p_md, &ex);
440                 RETURN_ON_EXCEPTION(this,ex);
441                 INT32_TO_NPVARIANT(val, result);
442                 return INVOKERESULT_NO_ERROR;
443             }
444             case ID_input_rate:
445             {
446                 float val = libvlc_media_player_get_rate(p_md, &ex);
447                 RETURN_ON_EXCEPTION(this,ex);
448                 DOUBLE_TO_NPVARIANT(val, result);
449                 return INVOKERESULT_NO_ERROR;
450             }
451             case ID_input_fps:
452             {
453                 double val = libvlc_media_player_get_fps(p_md, &ex);
454                 RETURN_ON_EXCEPTION(this,ex);
455                 DOUBLE_TO_NPVARIANT(val, result);
456                 return INVOKERESULT_NO_ERROR;
457             }
458             case ID_input_hasvout:
459             {
460                 bool val = p_plugin->player_has_vout(&ex);
461                 RETURN_ON_EXCEPTION(this,ex);
462                 BOOLEAN_TO_NPVARIANT(val, result);
463                 return INVOKERESULT_NO_ERROR;
464             }
465             default:
466                 ;
467         }
468     }
469     return INVOKERESULT_GENERIC_ERROR;
470 }
471
472 RuntimeNPObject::InvokeResult
473 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
474 {
475     /* is plugin still running */
476     if( isPluginRunning() )
477     {
478         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
479         libvlc_exception_t ex;
480         libvlc_exception_init(&ex);
481
482         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
483         RETURN_ON_EXCEPTION(this,ex);
484
485         switch( index )
486         {
487             case ID_input_position:
488             {
489                 if( ! NPVARIANT_IS_DOUBLE(value) )
490                 {
491                     return INVOKERESULT_INVALID_VALUE;
492                 }
493
494                 float val = (float)NPVARIANT_TO_DOUBLE(value);
495                 libvlc_media_player_set_position(p_md, val, &ex);
496                 RETURN_ON_EXCEPTION(this,ex);
497                 return INVOKERESULT_NO_ERROR;
498             }
499             case ID_input_time:
500             {
501                 int64_t val;
502                 if( NPVARIANT_IS_INT32(value) )
503                     val = (int64_t)NPVARIANT_TO_INT32(value);
504                 else if( NPVARIANT_IS_DOUBLE(value) )
505                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
506                 else
507                 {
508                     return INVOKERESULT_INVALID_VALUE;
509                 }
510
511                 libvlc_media_player_set_time(p_md, val, &ex);
512                 RETURN_ON_EXCEPTION(this,ex);
513                 return INVOKERESULT_NO_ERROR;
514             }
515             case ID_input_rate:
516             {
517                 float val;
518                 if( NPVARIANT_IS_INT32(value) )
519                     val = (float)NPVARIANT_TO_INT32(value);
520                 else if( NPVARIANT_IS_DOUBLE(value) )
521                     val = (float)NPVARIANT_TO_DOUBLE(value);
522                 else
523                 {
524                     return INVOKERESULT_INVALID_VALUE;
525                 }
526
527                 libvlc_media_player_set_rate(p_md, val, &ex);
528                 RETURN_ON_EXCEPTION(this,ex);
529                 return INVOKERESULT_NO_ERROR;
530             }
531             default:
532                 ;
533         }
534     }
535     return INVOKERESULT_GENERIC_ERROR;
536 }
537
538 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
539 {
540     /* no methods */
541 };
542
543 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
544
545 /*
546 ** implementation of libvlc playlist items object
547 */
548
549 const NPUTF8 * const LibvlcPlaylistItemsNPObject::propertyNames[] =
550 {
551     "count",
552 };
553 COUNTNAMES(LibvlcPlaylistItemsNPObject,propertyCount,propertyNames);
554
555 enum LibvlcPlaylistItemsNPObjectPropertyIds
556 {
557     ID_playlistitems_count,
558 };
559
560 RuntimeNPObject::InvokeResult
561 LibvlcPlaylistItemsNPObject::getProperty(int index, NPVariant &result)
562 {
563     /* is plugin still running */
564     if( isPluginRunning() )
565     {
566         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
567         libvlc_exception_t ex;
568         libvlc_exception_init(&ex);
569
570         switch( index )
571         {
572             case ID_playlistitems_count:
573             {
574                 int val = p_plugin->playlist_count(&ex);
575                 RETURN_ON_EXCEPTION(this,ex);
576                 INT32_TO_NPVARIANT(val, result);
577                 return INVOKERESULT_NO_ERROR;
578             }
579             default:
580                 ;
581         }
582     }
583     return INVOKERESULT_GENERIC_ERROR;
584 }
585
586 const NPUTF8 * const LibvlcPlaylistItemsNPObject::methodNames[] =
587 {
588     "clear",
589     "remove",
590 };
591 COUNTNAMES(LibvlcPlaylistItemsNPObject,methodCount,methodNames);
592
593 enum LibvlcPlaylistItemsNPObjectMethodIds
594 {
595     ID_playlistitems_clear,
596     ID_playlistitems_remove,
597 };
598
599 RuntimeNPObject::InvokeResult
600 LibvlcPlaylistItemsNPObject::invoke(int index, const NPVariant *args,
601                                     uint32_t argCount, NPVariant &result)
602 {
603     /* is plugin still running */
604     if( isPluginRunning() )
605     {
606         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
607         libvlc_exception_t ex;
608         libvlc_exception_init(&ex);
609
610         switch( index )
611         {
612             case ID_playlistitems_clear:
613                 if( argCount == 0 )
614                 {
615                     p_plugin->playlist_clear(&ex);
616                     RETURN_ON_EXCEPTION(this,ex);
617                     VOID_TO_NPVARIANT(result);
618                     return INVOKERESULT_NO_ERROR;
619                 }
620                 return INVOKERESULT_NO_SUCH_METHOD;
621             case ID_playlistitems_remove:
622                 if( (argCount == 1) && isNumberValue(args[0]) )
623                 {
624                     p_plugin->playlist_delete_item(numberValue(args[0]),&ex);
625                     RETURN_ON_EXCEPTION(this,ex);
626                     VOID_TO_NPVARIANT(result);
627                     return INVOKERESULT_NO_ERROR;
628                 }
629                 return INVOKERESULT_NO_SUCH_METHOD;
630             default:
631                 ;
632         }
633     }
634     return INVOKERESULT_GENERIC_ERROR;
635 }
636
637 /*
638 ** implementation of libvlc playlist object
639 */
640
641 LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()
642 {
643     if( isValid() )
644     {
645         if( playlistItemsObj ) NPN_ReleaseObject(playlistItemsObj);
646     }
647 };
648
649 const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] =
650 {
651     "itemCount", /* deprecated */
652     "isPlaying",
653     "items",
654 };
655 COUNTNAMES(LibvlcPlaylistNPObject,propertyCount,propertyNames);
656
657 enum LibvlcPlaylistNPObjectPropertyIds
658 {
659     ID_playlist_itemcount,
660     ID_playlist_isplaying,
661     ID_playlist_items,
662 };
663
664 RuntimeNPObject::InvokeResult
665 LibvlcPlaylistNPObject::getProperty(int index, NPVariant &result)
666 {
667     /* is plugin still running */
668     if( isPluginRunning() )
669     {
670         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
671         libvlc_exception_t ex;
672         libvlc_exception_init(&ex);
673
674         switch( index )
675         {
676             case ID_playlist_itemcount: /* deprecated */
677             {
678                 int val = p_plugin->playlist_count(&ex);
679                 RETURN_ON_EXCEPTION(this,ex);
680                 INT32_TO_NPVARIANT(val, result);
681                 return INVOKERESULT_NO_ERROR;
682             }
683             case ID_playlist_isplaying:
684             {
685                 int val = p_plugin->playlist_isplaying(&ex);
686                 RETURN_ON_EXCEPTION(this,ex);
687                 BOOLEAN_TO_NPVARIANT(val, result);
688                 return INVOKERESULT_NO_ERROR;
689             }
690             case ID_playlist_items:
691             {
692                 // create child object in lazyman fashion to avoid
693                 // ownership problem with firefox
694                 if( ! playlistItemsObj )
695                     playlistItemsObj =
696                         NPN_CreateObject(_instance, RuntimeNPClass<
697                         LibvlcPlaylistItemsNPObject>::getClass());
698                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
699                 return INVOKERESULT_NO_ERROR;
700             }
701             default:
702                 ;
703         }
704     }
705     return INVOKERESULT_GENERIC_ERROR;
706 }
707
708 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
709 {
710     "add",
711     "play",
712     "playItem",
713     "togglePause",
714     "stop",
715     "next",
716     "prev",
717     "clear", /* deprecated */
718     "removeItem", /* deprecated */
719 };
720 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
721
722 enum LibvlcPlaylistNPObjectMethodIds
723 {
724     ID_playlist_add,
725     ID_playlist_play,
726     ID_playlist_playItem,
727     ID_playlist_togglepause,
728     ID_playlist_stop,
729     ID_playlist_next,
730     ID_playlist_prev,
731     ID_playlist_clear,
732     ID_playlist_removeitem
733 };
734
735 RuntimeNPObject::InvokeResult
736 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
737                                uint32_t argCount, NPVariant &result)
738 {
739     /* is plugin still running */
740     if( isPluginRunning() )
741     {
742         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
743         libvlc_exception_t ex;
744         libvlc_exception_init(&ex);
745
746         switch( index )
747         {
748             // XXX FIXME this needs squashing into something much smaller
749             case ID_playlist_add:
750             {
751                 if( (argCount < 1) || (argCount > 3) )
752                     return INVOKERESULT_NO_SUCH_METHOD;
753
754                 char *url = NULL;
755
756                 // grab URL
757                 if( NPVARIANT_IS_STRING(args[0]) )
758                 {
759                     char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
760                     if( s )
761                     {
762                         url = p_plugin->getAbsoluteURL(s);
763                         if( url )
764                             free(s);
765                         else
766                             // problem with combining url, use argument
767                             url = s;
768                     }
769                     else
770                         return INVOKERESULT_OUT_OF_MEMORY;
771                 }
772                 else
773                     return INVOKERESULT_NO_SUCH_METHOD;
774
775                 char *name = NULL;
776
777                 // grab name if available
778                 if( argCount > 1 )
779                 {
780                     if( NPVARIANT_IS_NULL(args[1]) )
781                     {
782                         // do nothing
783                     }
784                     else if( NPVARIANT_IS_STRING(args[1]) )
785                     {
786                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
787                     }
788                     else
789                     {
790                         free(url);
791                         return INVOKERESULT_INVALID_VALUE;
792                     }
793                 }
794
795                 int i_options = 0;
796                 char** ppsz_options = NULL;
797
798                 // grab options if available
799                 if( argCount > 2 )
800                 {
801                     if( NPVARIANT_IS_NULL(args[2]) )
802                     {
803                         // do nothing
804                     }
805                     else if( NPVARIANT_IS_STRING(args[2]) )
806                     {
807                         parseOptions(NPVARIANT_TO_STRING(args[2]),
808                                      &i_options, &ppsz_options);
809
810                     }
811                     else if( NPVARIANT_IS_OBJECT(args[2]) )
812                     {
813                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
814                                      &i_options, &ppsz_options);
815                     }
816                     else
817                     {
818                         free(url);
819                         free(name);
820                         return INVOKERESULT_INVALID_VALUE;
821                     }
822                 }
823
824                 int item = p_plugin->playlist_add_extended_untrusted(url, name, i_options,
825                                const_cast<const char **>(ppsz_options), &ex);
826                 free(url);
827                 free(name);
828                 for( int i=0; i< i_options; ++i )
829                 {
830                     free(ppsz_options[i]);
831                 }
832                 free(ppsz_options);
833
834                 RETURN_ON_EXCEPTION(this,ex);
835                 INT32_TO_NPVARIANT(item, result);
836                 return INVOKERESULT_NO_ERROR;
837             }
838             case ID_playlist_play:
839                 if( argCount == 0 )
840                 {
841                     p_plugin->playlist_play(&ex);
842                     RETURN_ON_EXCEPTION(this,ex);
843                     VOID_TO_NPVARIANT(result);
844                     return INVOKERESULT_NO_ERROR;
845                 }
846                 return INVOKERESULT_NO_SUCH_METHOD;
847             case ID_playlist_playItem:
848                 if( (argCount == 1) && isNumberValue(args[0]) )
849                 {
850                     p_plugin->playlist_play_item(numberValue(args[0]),&ex);
851                     RETURN_ON_EXCEPTION(this,ex);
852                     VOID_TO_NPVARIANT(result);
853                     return INVOKERESULT_NO_ERROR;
854                 }
855                 return INVOKERESULT_NO_SUCH_METHOD;
856             case ID_playlist_togglepause:
857                 if( argCount == 0 )
858                 {
859                     p_plugin->playlist_pause(&ex);
860                     RETURN_ON_EXCEPTION(this,ex);
861                     VOID_TO_NPVARIANT(result);
862                     return INVOKERESULT_NO_ERROR;
863                 }
864                 return INVOKERESULT_NO_SUCH_METHOD;
865             case ID_playlist_stop:
866                 if( argCount == 0 )
867                 {
868                     p_plugin->playlist_stop(&ex);
869                     RETURN_ON_EXCEPTION(this,ex);
870                     VOID_TO_NPVARIANT(result);
871                     return INVOKERESULT_NO_ERROR;
872                 }
873                 return INVOKERESULT_NO_SUCH_METHOD;
874             case ID_playlist_next:
875                 if( argCount == 0 )
876                 {
877                     p_plugin->playlist_next(&ex);
878                     RETURN_ON_EXCEPTION(this,ex);
879                     VOID_TO_NPVARIANT(result);
880                     return INVOKERESULT_NO_ERROR;
881                 }
882                 return INVOKERESULT_NO_SUCH_METHOD;
883             case ID_playlist_prev:
884                 if( argCount == 0 )
885                 {
886                     p_plugin->playlist_prev(&ex);
887                     RETURN_ON_EXCEPTION(this,ex);
888                     VOID_TO_NPVARIANT(result);
889                     return INVOKERESULT_NO_ERROR;
890                 }
891                 return INVOKERESULT_NO_SUCH_METHOD;
892             case ID_playlist_clear: /* deprecated */
893                 if( argCount == 0 )
894                 {
895                     p_plugin->playlist_clear(&ex);
896                     RETURN_ON_EXCEPTION(this,ex);
897                     VOID_TO_NPVARIANT(result);
898                     return INVOKERESULT_NO_ERROR;
899                 }
900                 return INVOKERESULT_NO_SUCH_METHOD;
901             case ID_playlist_removeitem: /* deprecated */
902                 if( (argCount == 1) && isNumberValue(args[0]) )
903                 {
904                     p_plugin->playlist_delete_item(numberValue(args[0]), &ex);
905                     RETURN_ON_EXCEPTION(this,ex);
906                     VOID_TO_NPVARIANT(result);
907                     return INVOKERESULT_NO_ERROR;
908                 }
909                 return INVOKERESULT_NO_SUCH_METHOD;
910             default:
911                 ;
912         }
913     }
914     return INVOKERESULT_GENERIC_ERROR;
915 }
916
917 // XXX FIXME The new playlist_add creates a media instance and feeds it
918 // XXX FIXME these options one at a time, so this hunk of code does lots
919 // XXX FIXME of unnecessairy work. Break out something that can do one
920 // XXX FIXME option at a time and doesn't need to realloc().
921 // XXX FIXME Same for the other version of parseOptions.
922
923 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
924                                          int *i_options, char*** ppsz_options)
925 {
926     if( nps.utf8length )
927     {
928         char *s = stringValue(nps);
929         char *val = s;
930         if( val )
931         {
932             long capacity = 16;
933             char **options = (char **)malloc(capacity*sizeof(char *));
934             if( options )
935             {
936                 int nOptions = 0;
937
938                 char *end = val + nps.utf8length;
939                 while( val < end )
940                 {
941                     // skip leading blanks
942                     while( (val < end)
943                         && ((*val == ' ' ) || (*val == '\t')) )
944                         ++val;
945
946                     char *start = val;
947                     // skip till we get a blank character
948                     while( (val < end)
949                         && (*val != ' ' )
950                         && (*val != '\t') )
951                     {
952                         char c = *(val++);
953                         if( ('\'' == c) || ('"' == c) )
954                         {
955                             // skip till end of string
956                             while( (val < end) && (*(val++) != c ) );
957                         }
958                     }
959
960                     if( val > start )
961                     {
962                         if( nOptions == capacity )
963                         {
964                             capacity += 16;
965                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
966                             if( ! moreOptions )
967                             {
968                                 /* failed to allocate more memory */
969                                 free(s);
970                                 /* return what we got so far */
971                                 *i_options = nOptions;
972                                 *ppsz_options = options;
973                                 return;
974                             }
975                             options = moreOptions;
976                         }
977                         *(val++) = '\0';
978                         options[nOptions++] = strdup(start);
979                     }
980                     else
981                         // must be end of string
982                         break;
983                 }
984                 *i_options = nOptions;
985                 *ppsz_options = options;
986             }
987             free(s);
988         }
989     }
990 }
991
992 // XXX FIXME See comment at the other parseOptions variant.
993 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
994                                           char*** ppsz_options)
995 {
996     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
997
998     NPVariant value;
999
1000     /* we are expecting to have a Javascript Array object */
1001     NPIdentifier propId = NPN_GetStringIdentifier("length");
1002     if( NPN_GetProperty(_instance, obj, propId, &value) )
1003     {
1004         int count = numberValue(value);
1005         NPN_ReleaseVariantValue(&value);
1006
1007         if( count )
1008         {
1009             long capacity = 16;
1010             char **options = (char **)malloc(capacity*sizeof(char *));
1011             if( options )
1012             {
1013                 int nOptions = 0;
1014
1015                 while( nOptions < count )
1016                 {
1017                     propId = NPN_GetIntIdentifier(nOptions);
1018                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
1019                         /* return what we got so far */
1020                         break;
1021
1022                     if( ! NPVARIANT_IS_STRING(value) )
1023                     {
1024                         /* return what we got so far */
1025                         NPN_ReleaseVariantValue(&value);
1026                         break;
1027                     }
1028
1029                     if( nOptions == capacity )
1030                     {
1031                         capacity += 16;
1032                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1033                         if( ! moreOptions )
1034                         {
1035                             /* failed to allocate more memory */
1036                             NPN_ReleaseVariantValue(&value);
1037                             /* return what we got so far */
1038                             *i_options = nOptions;
1039                             *ppsz_options = options;
1040                             break;
1041                         }
1042                         options = moreOptions;
1043                     }
1044
1045                     options[nOptions++] = stringValue(value);
1046                 }
1047                 *i_options = nOptions;
1048                 *ppsz_options = options;
1049             }
1050         }
1051     }
1052 }
1053
1054 /*
1055 ** implementation of libvlc video object
1056 */
1057
1058 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
1059 {
1060     "fullscreen",
1061     "height",
1062     "width",
1063     "aspectRatio",
1064     "subtitle",
1065     "crop",
1066     "teletext"
1067 };
1068
1069 enum LibvlcVideoNPObjectPropertyIds
1070 {
1071     ID_video_fullscreen,
1072     ID_video_height,
1073     ID_video_width,
1074     ID_video_aspectratio,
1075     ID_video_subtitle,
1076     ID_video_crop,
1077     ID_video_teletext
1078 };
1079 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1080
1081 RuntimeNPObject::InvokeResult
1082 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1083 {
1084     /* is plugin still running */
1085     if( isPluginRunning() )
1086     {
1087         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1088         libvlc_exception_t ex;
1089         libvlc_exception_init(&ex);
1090
1091         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1092         RETURN_ON_EXCEPTION(this,ex);
1093
1094         switch( index )
1095         {
1096             case ID_video_fullscreen:
1097             {
1098                 int val = p_plugin->get_fullscreen(&ex);
1099                 RETURN_ON_EXCEPTION(this,ex);
1100                 BOOLEAN_TO_NPVARIANT(val, result);
1101                 return INVOKERESULT_NO_ERROR;
1102             }
1103             case ID_video_height:
1104             {
1105                 int val = libvlc_video_get_height(p_md, &ex);
1106                 RETURN_ON_EXCEPTION(this,ex);
1107                 INT32_TO_NPVARIANT(val, result);
1108                 return INVOKERESULT_NO_ERROR;
1109             }
1110             case ID_video_width:
1111             {
1112                 int val = libvlc_video_get_width(p_md, &ex);
1113                 RETURN_ON_EXCEPTION(this,ex);
1114                 INT32_TO_NPVARIANT(val, result);
1115                 return INVOKERESULT_NO_ERROR;
1116             }
1117             case ID_video_aspectratio:
1118             {
1119                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1120                 RETURN_ON_EXCEPTION(this,ex);
1121                 if( !psz_aspect )
1122                     return INVOKERESULT_GENERIC_ERROR;
1123
1124                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1125                 return INVOKERESULT_NO_ERROR;
1126             }
1127             case ID_video_subtitle:
1128             {
1129                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1130                 RETURN_ON_EXCEPTION(this,ex);
1131                 INT32_TO_NPVARIANT(i_spu, result);
1132                 return INVOKERESULT_NO_ERROR;
1133             }
1134             case ID_video_crop:
1135             {
1136                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1137                 RETURN_ON_EXCEPTION(this,ex);
1138                 if( !psz_geometry )
1139                     return INVOKERESULT_GENERIC_ERROR;
1140
1141                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1142                 return INVOKERESULT_NO_ERROR;
1143             }
1144             case ID_video_teletext:
1145             {
1146                 int i_page = libvlc_video_get_teletext(p_md, &ex);
1147                 RETURN_ON_EXCEPTION(this,ex);
1148                 INT32_TO_NPVARIANT(i_page, result);
1149                 return INVOKERESULT_NO_ERROR;
1150             }
1151         }
1152     }
1153     return INVOKERESULT_GENERIC_ERROR;
1154 }
1155
1156 RuntimeNPObject::InvokeResult
1157 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1158 {
1159     /* is plugin still running */
1160     if( isPluginRunning() )
1161     {
1162         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1163         libvlc_exception_t ex;
1164         libvlc_exception_init(&ex);
1165
1166         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1167         RETURN_ON_EXCEPTION(this,ex);
1168
1169         switch( index )
1170         {
1171             case ID_video_fullscreen:
1172             {
1173                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1174                 {
1175                     return INVOKERESULT_INVALID_VALUE;
1176                 }
1177
1178                 int val = NPVARIANT_TO_BOOLEAN(value);
1179                 p_plugin->set_fullscreen(val, &ex);
1180                 RETURN_ON_EXCEPTION(this,ex);
1181                 return INVOKERESULT_NO_ERROR;
1182             }
1183             case ID_video_aspectratio:
1184             {
1185                 char *psz_aspect = NULL;
1186
1187                 if( ! NPVARIANT_IS_STRING(value) )
1188                 {
1189                     return INVOKERESULT_INVALID_VALUE;
1190                 }
1191
1192                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1193                 if( !psz_aspect )
1194                 {
1195                     return INVOKERESULT_GENERIC_ERROR;
1196                 }
1197
1198                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1199                 free(psz_aspect);
1200                 RETURN_ON_EXCEPTION(this,ex);
1201
1202                 return INVOKERESULT_NO_ERROR;
1203             }
1204             case ID_video_subtitle:
1205             {
1206                 if( isNumberValue(value) )
1207                 {
1208                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1209                     RETURN_ON_EXCEPTION(this,ex);
1210
1211                     return INVOKERESULT_NO_ERROR;
1212                 }
1213                 return INVOKERESULT_INVALID_VALUE;
1214             }
1215             case ID_video_crop:
1216             {
1217                 char *psz_geometry = NULL;
1218
1219                 if( ! NPVARIANT_IS_STRING(value) )
1220                 {
1221                     return INVOKERESULT_INVALID_VALUE;
1222                 }
1223
1224                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1225                 if( !psz_geometry )
1226                 {
1227                     return INVOKERESULT_GENERIC_ERROR;
1228                 }
1229
1230                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1231                 free(psz_geometry);
1232                 RETURN_ON_EXCEPTION(this,ex);
1233
1234                 return INVOKERESULT_NO_ERROR;
1235             }
1236             case ID_video_teletext:
1237             {
1238                 if( isNumberValue(value) )
1239                 {
1240                     libvlc_video_set_teletext(p_md, numberValue(value), &ex);
1241                     RETURN_ON_EXCEPTION(this,ex);
1242
1243                     return INVOKERESULT_NO_ERROR;
1244                 }
1245                 return INVOKERESULT_INVALID_VALUE;
1246             }
1247         }
1248     }
1249     return INVOKERESULT_GENERIC_ERROR;
1250 }
1251
1252 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1253 {
1254     "toggleFullscreen",
1255     "toggleTeletext"
1256 };
1257 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1258
1259 enum LibvlcVideoNPObjectMethodIds
1260 {
1261     ID_video_togglefullscreen,
1262     ID_video_toggleteletext
1263 };
1264
1265 RuntimeNPObject::InvokeResult
1266 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1267                             uint32_t argCount, NPVariant &result)
1268 {
1269     /* is plugin still running */
1270     if( isPluginRunning() )
1271     {
1272         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1273         libvlc_exception_t ex;
1274         libvlc_exception_init(&ex);
1275
1276         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1277         RETURN_ON_EXCEPTION(this,ex);
1278
1279         switch( index )
1280         {
1281             case ID_video_togglefullscreen:
1282                 if( argCount == 0 )
1283                 {
1284                     p_plugin->toggle_fullscreen(&ex);
1285                     RETURN_ON_EXCEPTION(this,ex);
1286                     VOID_TO_NPVARIANT(result);
1287                     return INVOKERESULT_NO_ERROR;
1288                 }
1289                 return INVOKERESULT_NO_SUCH_METHOD;
1290             case ID_video_toggleteletext:
1291                 if( argCount == 0 )
1292                 {
1293                     libvlc_toggle_teletext(p_md, &ex);
1294                     RETURN_ON_EXCEPTION(this,ex);
1295                     VOID_TO_NPVARIANT(result);
1296                     return INVOKERESULT_NO_ERROR;
1297                 }
1298                 return INVOKERESULT_NO_SUCH_METHOD;
1299             default:
1300                 return INVOKERESULT_NO_SUCH_METHOD;
1301         }
1302     }
1303     return INVOKERESULT_GENERIC_ERROR;
1304 }