+#if defined(XP_UNIX)
+# include <pthread.h>
+#elif defined(XP_WIN)
+ /* windows headers */
+# include <winbase.h>
+#else
+#warning "locking not implemented for this platform"
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+/*****************************************************************************
+ * utilitiy functions
+ *****************************************************************************/
+static void plugin_lock_init(plugin_lock_t *lock)
+{
+ assert(lock);
+
+#if defined(XP_UNIX)
+ pthread_mutex_init(&lock->mutex, NULL);
+#elif defined(XP_WIN)
+ InitializeCriticalSection(&lock->cs);
+#else
+#warning "locking not implemented in this platform"
+#endif
+}
+
+static void plugin_lock_destroy(plugin_lock_t *lock)
+{
+ assert(lock);
+
+#if defined(XP_UNIX)
+ pthread_mutex_destroy(&lock->mutex);
+#elif defined(XP_WIN)
+ DeleteCriticalSection(&lock->cs);
+#else
+#warning "locking not implemented in this platform"
+#endif
+}
+
+static void plugin_lock(plugin_lock_t *lock)
+{
+ assert(lock);
+
+#if defined(XP_UNIX)
+ pthread_mutex_lock(&lock->mutex);
+#elif defined(XP_WIN)
+ EnterCriticalSection(&lock->cs);
+#else
+#warning "locking not implemented in this platform"
+#endif
+}
+
+static void plugin_unlock(plugin_lock_t *lock)
+{
+ assert(lock);
+
+#if defined(XP_UNIX)
+ pthread_mutex_unlock(&lock->mutex);
+#elif defined(XP_WIN)
+ LeaveCriticalSection(&lock->cs);
+#else
+#warning "locking not implemented in this platform"
+#endif
+}
+
+/*****************************************************************************
+ * Event Object
+ *****************************************************************************/
+static void handle_input_event(const libvlc_event_t* event, void *param);
+static void handle_changed_event(const libvlc_event_t* event, void *param);
+
+static vlcplugin_event_t vlcevents[] = {
+ { "MediaPlayerMediaChanged", libvlc_MediaPlayerMediaChanged, handle_input_event },
+ { "MediaPlayerNothingSpecial", libvlc_MediaPlayerNothingSpecial, handle_input_event },
+ { "MediaPlayerOpening", libvlc_MediaPlayerOpening, handle_input_event },
+ { "MediaPlayerBuffering", libvlc_MediaPlayerBuffering, handle_changed_event },
+ { "MediaPlayerPlaying", libvlc_MediaPlayerPlaying, handle_input_event },
+ { "MediaPlayerPaused", libvlc_MediaPlayerPaused, handle_input_event },
+ { "MediaPlayerStopped", libvlc_MediaPlayerStopped, handle_input_event },
+ { "MediaPlayerForward", libvlc_MediaPlayerForward, handle_input_event },
+ { "MediaPlayerBackward", libvlc_MediaPlayerBackward, handle_input_event },
+ { "MediaPlayerEndReached", libvlc_MediaPlayerEndReached, handle_input_event },
+ { "MediaPlayerEncounteredError", libvlc_MediaPlayerEncounteredError, handle_input_event },
+ { "MediaPlayerTimeChanged", libvlc_MediaPlayerTimeChanged, handle_changed_event },
+ { "MediaPlayerPositionChanged", libvlc_MediaPlayerPositionChanged, handle_changed_event },
+ { "MediaPlayerSeekableChanged", libvlc_MediaPlayerSeekableChanged, handle_changed_event },
+ { "MediaPlayerPausableChanged", libvlc_MediaPlayerPausableChanged, handle_changed_event },
+ { "MediaPlayerTitleChanged", libvlc_MediaPlayerTitleChanged, handle_changed_event },
+ { "MediaPlayerLengthChanged", libvlc_MediaPlayerLengthChanged, handle_changed_event },
+};
+
+static void handle_input_event(const libvlc_event_t* event, void *param)
+{
+ VlcPlugin *plugin = (VlcPlugin*)param;
+ switch( event->type )
+ {
+ case libvlc_MediaPlayerNothingSpecial:
+ case libvlc_MediaPlayerOpening:
+ case libvlc_MediaPlayerPlaying:
+ case libvlc_MediaPlayerPaused:
+ case libvlc_MediaPlayerStopped:
+ case libvlc_MediaPlayerForward:
+ case libvlc_MediaPlayerBackward:
+ case libvlc_MediaPlayerEndReached:
+ case libvlc_MediaPlayerEncounteredError:
+ plugin->event_callback(event, NULL, 0, param);
+ break;
+ default: /* ignore all other libvlc_event_type_t */
+ break;
+ }
+}
+
+static void handle_changed_event(const libvlc_event_t* event, void *param)
+{
+ uint32_t npcount = 1;
+ NPVariant *npparam = (NPVariant *) NPN_MemAlloc( sizeof(NPVariant) * npcount );
+
+ VlcPlugin *plugin = (VlcPlugin*)param;
+ switch( event->type )
+ {
+ case libvlc_MediaPlayerBuffering:
+ DOUBLE_TO_NPVARIANT(event->u.media_player_buffering.new_cache, npparam[0]);
+ break;
+ case libvlc_MediaPlayerTimeChanged:
+ DOUBLE_TO_NPVARIANT(event->u.media_player_time_changed.new_time, npparam[0]);
+ break;
+ case libvlc_MediaPlayerPositionChanged:
+ DOUBLE_TO_NPVARIANT(event->u.media_player_position_changed.new_position, npparam[0]);
+ break;
+ case libvlc_MediaPlayerSeekableChanged:
+ BOOLEAN_TO_NPVARIANT(event->u.media_player_seekable_changed.new_seekable, npparam[0]);
+ break;
+ case libvlc_MediaPlayerPausableChanged:
+ BOOLEAN_TO_NPVARIANT(event->u.media_player_pausable_changed.new_pausable, npparam[0]);
+ break;
+ case libvlc_MediaPlayerTitleChanged:
+ BOOLEAN_TO_NPVARIANT(event->u.media_player_title_changed.new_title, npparam[0]);
+ break;
+ case libvlc_MediaPlayerLengthChanged:
+ DOUBLE_TO_NPVARIANT(event->u.media_player_length_changed.new_length, npparam[0]);
+ break;
+ default: /* ignore all other libvlc_event_type_t */
+ NPN_MemFree( npparam );
+ return;
+ }
+ plugin->event_callback(event, npparam, npcount, param);
+}
+
+bool EventObj::init()
+{
+ plugin_lock_init(&lock);
+ return true;
+}
+
+EventObj::~EventObj()
+{
+ plugin_lock_destroy(&lock);
+}
+
+void EventObj::deliver(NPP browser)
+{
+ plugin_lock(&lock);
+
+ for( ev_l::iterator iter = _elist.begin(); iter != _elist.end(); ++iter )
+ {
+ for( lr_l::iterator j = _llist.begin(); j != _llist.end(); ++j )
+ {
+ if( j->event_type() == iter->event_type() )
+ {
+ NPVariant result;
+ NPVariant *params = iter->params();
+ uint32_t count = iter->count();
+
+ NPObject *listener = j->listener();
+ assert( listener );
+
+ NPN_InvokeDefault( browser, listener, params, count, &result );
+ NPN_ReleaseVariantValue( &result );
+
+ for( uint32_t n = 0; n < count; n++ )
+ {
+ if( NPVARIANT_IS_STRING(params[n]) )
+ NPN_MemFree( (void*) NPVARIANT_TO_STRING(params[n]).UTF8Characters );
+ else if( NPVARIANT_IS_OBJECT(params[n]) )
+ {
+ NPN_ReleaseObject( NPVARIANT_TO_OBJECT(params[n]) );
+ NPN_MemFree( (void*)NPVARIANT_TO_OBJECT(params[n]) );
+ }
+ }
+ if (params) NPN_MemFree( params );
+ }
+ }
+ }
+ _elist.clear();
+
+ plugin_unlock(&lock);
+}
+
+void EventObj::callback(const libvlc_event_t* event,
+ NPVariant *npparams, uint32_t count)
+{
+ plugin_lock(&lock);
+ _elist.push_back(VLCEvent(event->type, npparams, count));
+ plugin_unlock(&lock);
+}
+
+vlcplugin_event_t *EventObj::find_event(const char *s) const
+{
+ for( int i = 0; i < ARRAY_SIZE(vlcevents); i++ )
+ {
+ if( strncmp(vlcevents[i].name, s, strlen(vlcevents[i].name)) == 0 )
+ return &vlcevents[i];
+ }
+ return NULL;
+}
+
+const char *EventObj::find_name(const libvlc_event_t *event)
+{
+ for( int i = 0; i < ARRAY_SIZE(vlcevents); i++ )
+ {
+ if( vlcevents[i].libvlc_type == event->type )
+ return vlcevents[i].name;
+ }
+ return NULL;
+}
+
+bool EventObj::insert(const NPString &name, NPObject *listener, bool bubble)
+{
+ vlcplugin_event_t *event = find_event(name.UTF8Characters);
+ if( !event )
+ return false;
+
+ lr_l::iterator iter;
+ for( iter = _llist.begin(); iter != _llist.end(); ++iter )
+ if( iter->listener() == listener && iter->bubble() == bubble )
+ break;
+
+ if( iter == _llist.end() )
+ {
+ _llist.push_back(Listener(event, listener, bubble));
+ return true;
+ }
+
+ return false;
+}
+
+bool EventObj::remove(const NPString &name, NPObject *listener, bool bubble)
+{
+ vlcplugin_event_t *event = find_event(name.UTF8Characters);
+ if( !event )
+ return false;
+
+ for( lr_l::iterator iter = _llist.begin(); iter !=_llist.end(); iter++ )
+ {
+ if( iter->event_type() == event->libvlc_type &&
+ iter->listener() == listener &&
+ iter->bubble() == bubble )
+ {
+ iter = _llist.erase(iter);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void EventObj::hook_manager( libvlc_event_manager_t *em, void *userdata )
+{
+ _em = em;
+
+ if( _em )
+ {
+ /* attach all libvlc events we care about */
+ for( int i = 0; i < ARRAY_SIZE(vlcevents); i++ )
+ {
+ libvlc_event_attach( _em, vlcevents[i].libvlc_type,
+ vlcevents[i].libvlc_callback,
+ userdata );
+ }
+ }
+}
+
+void EventObj::unhook_manager( void *userdata )
+{
+ if( _em )
+ {
+ /* detach all libvlc events we cared about */
+ for( int i = 0; i < ARRAY_SIZE(vlcevents); i++ )
+ {
+ libvlc_event_detach( _em, vlcevents[i].libvlc_type,
+ vlcevents[i].libvlc_callback,
+ userdata );
+ }
+ }
+}
+