]> git.sesse.net Git - vlc/commitdiff
mozilla plugin: rework events listeners to dom level 2 type, sort of.
authorJP Dinger <jpd@videolan.org>
Fri, 29 Jan 2010 15:30:26 +0000 (16:30 +0100)
committerJP Dinger <jpd@videolan.org>
Fri, 29 Jan 2010 15:56:37 +0000 (16:56 +0100)
projects/mozilla/control/npolibvlc.cpp
projects/mozilla/control/npolibvlc.h
projects/mozilla/vlcplugin.cpp
projects/mozilla/vlcplugin.h

index 976d7733e50aea8021596d0ec42c58185971232c..2efe11688c33e87c9b0079ff25501730782c8633 100644 (file)
@@ -76,45 +76,6 @@ NPVariant copyNPVariant(const NPVariant& original)
     return res;
 }
 
-// Parse an event Array given as a NPObject by JS.
-// This function is similar to LibvlcPlaylistNPObject::parseOptions,
-// but we don't use it because it's not clearly accessible and the FIXME flags
-// implie that it might be modified.
-bool parseEventArray(NPObject *obj, eventtypes_bitmap_t &eventToGet, NPP instance)
-{
-    NPIdentifier propId = NPN_GetStringIdentifier("length");
-    NPVariant value;
-
-    if (!NPN_GetProperty(instance, obj, propId, &value))
-        return false;
-
-    int count = NPVARIANT_TO_INT32(value);
-    NPN_ReleaseVariantValue(&value);
-    if (count == 0)
-        return false;
-
-    int nOptions = 0;
-    while (nOptions < count)
-    {
-        propId = NPN_GetIntIdentifier(nOptions);
-        // if there is no other string in the array.
-        if( ! NPN_GetProperty(instance, obj, propId, &value) )
-            break;
-
-        // if the element is not a string.
-        if( ! NPVARIANT_IS_STRING(value) )
-        {
-            NPN_ReleaseVariantValue(&value);
-            break;
-        }
-
-        if (!eventToGet.add_event(NPVARIANT_TO_STRING(value).utf8characters))
-            return false;
-        nOptions++;
-    }
-    return true;
-}
-
 /*
 ** implementation of libvlc root object
 */
@@ -134,6 +95,7 @@ LibvlcRootNPObject::~LibvlcRootNPObject()
         if( audioObj    ) NPN_ReleaseObject(audioObj);
         if( inputObj    ) NPN_ReleaseObject(inputObj);
         if( playlistObj ) NPN_ReleaseObject(playlistObj);
+        if( subtitleObj ) NPN_ReleaseObject(subtitleObj);
         if( videoObj    ) NPN_ReleaseObject(videoObj);
     }
 }
@@ -145,7 +107,6 @@ const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
     "playlist",
     "subtitle",
     "video",
-    "events",
     "VersionInfo",
 };
 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
@@ -157,7 +118,6 @@ enum LibvlcRootNPObjectPropertyIds
     ID_root_playlist,
     ID_root_subtitle,
     ID_root_video,
-    ID_root_events,
     ID_root_VersionInfo,
 };
 
@@ -189,14 +149,6 @@ LibvlcRootNPObject::getProperty(int index, NPVariant &result)
                 InstantObj<LibvlcVideoNPObject>( videoObj );
                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
                 return INVOKERESULT_NO_ERROR;
-            case ID_root_events:
-                // create child object in lazyman fashion to avoid
-                // ownership problem with firefox
-                if( ! eventObj )
-                    eventObj = NPN_CreateObject(_instance,
-                             RuntimeNPClass<LibvlcEventNPObject>::getClass());
-                OBJECT_TO_NPVARIANT(NPN_RetainObject(eventObj), result);
-                return INVOKERESULT_NO_ERROR;
             case ID_root_VersionInfo:
                 return invokeResultString(libvlc_get_version(),result);
             default:
@@ -209,34 +161,65 @@ LibvlcRootNPObject::getProperty(int index, NPVariant &result)
 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
 {
     "versionInfo",
+    "addEventListener",
+    "removeEventListener",
 };
 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
 
 enum LibvlcRootNPObjectMethodIds
 {
     ID_root_versionInfo,
+    ID_root_addeventlistener,
+    ID_root_removeeventlistener,
 };
 
 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
                   const NPVariant *args, uint32_t argCount, NPVariant &result)
 {
     /* is plugin still running */
-    if( isPluginRunning() )
+    if( !isPluginRunning() )
+        return INVOKERESULT_GENERIC_ERROR;
+
+    libvlc_exception_t ex;
+    libvlc_exception_init(&ex);
+
+    switch( index )
     {
-        libvlc_exception_t ex;
-        libvlc_exception_init(&ex);
+    case ID_root_versionInfo:
+        if( 0 != argCount )
+            return INVOKERESULT_NO_SUCH_METHOD;
+        return invokeResultString(libvlc_get_version(),result);
+
+    case ID_root_addeventlistener:
+    case ID_root_removeeventlistener:
+        if( (3 != argCount) ||
+            !NPVARIANT_IS_STRING(args[0]) ||
+            !NPVARIANT_IS_OBJECT(args[1]) ||
+            !NPVARIANT_IS_BOOLEAN(args[2]) )
+            break;
 
-        switch( index )
+        if( !VlcPlugin::canUseEventListener() )
         {
-            case ID_root_versionInfo:
-                if( 0 != argCount )
-                    return INVOKERESULT_NO_SUCH_METHOD;
-                return invokeResultString(libvlc_get_version(),result);
-            default:
-                ;
+            NPN_SetException(this, ERROR_API_VERSION);
+            return INVOKERESULT_GENERIC_ERROR;
         }
+
+        NPObject *listener = NPVARIANT_TO_OBJECT(args[1]);
+        VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
+
+        bool b;
+        if(ID_root_removeeventlistener!=index)
+            b = p_plugin->events.insert(NPVARIANT_TO_STRING(args[0]),
+                                     listener, NPVARIANT_TO_BOOLEAN(args[2]));
+        else
+            b = p_plugin->events.remove(NPVARIANT_TO_STRING(args[0]),
+                                     listener, NPVARIANT_TO_BOOLEAN(args[2]));
+
+        VOID_TO_NPVARIANT(result);
+
+        return b ? INVOKERESULT_NO_ERROR : INVOKERESULT_GENERIC_ERROR;
     }
-    return INVOKERESULT_GENERIC_ERROR;
+    return INVOKERESULT_NO_SUCH_METHOD;
 }
 
 /*
@@ -2061,125 +2044,3 @@ LibvlcDeinterlaceNPObject::invoke(int index, const NPVariant *args,
     return INVOKERESULT_NO_ERROR;
 }
 
-
-
-/*
-** implementation of libvlc event object
-*/
-
-const NPUTF8 * const LibvlcEventNPObject::propertyNames[] =
-{
-};
-
-enum LibvlcEventNPObjectPropertyIds
-{
-};
-COUNTNAMES(LibvlcEventNPObject,propertyCount,propertyNames);
-
-const NPUTF8 * const LibvlcEventNPObject::methodNames[] =
-{
-    "addListener",
-    "removeListeners",
-};
-COUNTNAMES(LibvlcEventNPObject,methodCount,methodNames);
-
-enum LibvlcEventNPObjectMethodIds
-{
-    ID_event_addListener,
-    ID_event_removeListeners,
-};
-
-bool LibvlcEventNPObject::parseArgs(const NPVariant *args, uint32_t argCount,
-                                    eventtypes_bitmap_t &eventToGet)
-{
-    if (argCount > 2)
-        eventToGet.clear();
-
-    for (int argIndex = 2; argIndex < argCount; argIndex++)
-    {
-        if (NPVARIANT_IS_STRING(args[argIndex]))
-        {
-            if (!eventToGet.add_event(NPVARIANT_TO_STRING(args[argIndex]).utf8characters))
-                return false;
-        }
-        else if (NPVARIANT_IS_OBJECT(args[argIndex]))
-        {
-            if (!parseEventArray(NPVARIANT_TO_OBJECT(args[argIndex]), eventToGet, _instance))
-                return false;
-        }
-        else
-            return false;
-    }
-    return true;
-}
-
-RuntimeNPObject::InvokeResult
-LibvlcEventNPObject::invoke(int index, const NPVariant *args,
-                            uint32_t argCount, NPVariant &result)
-{
-    /* is plugin still running */
-    if( isPluginRunning() )
-    {
-        libvlc_exception_t ex;
-        libvlc_exception_init(&ex);
-
-        switch( index )
-        {
-            case ID_event_addListener:
-                if (argCount >= 2)
-                {
-                    // Checks if the first argument is a NPObject
-                    if (!NPVARIANT_IS_OBJECT(args[0]))
-                        return INVOKERESULT_NO_SUCH_METHOD;
-
-                    // Checks if the browser has the NPAPI version 0.19 at least.
-                    if (!VlcPlugin::canUseEventListener())
-                    {
-                      NPN_SetException(this, strdup(ERROR_API_VERSION));
-                      return INVOKERESULT_GENERIC_ERROR;
-                    }
-
-                    VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
-
-                    // Gets the binary field corresponding to the events the
-                    // listener must listen to if specified.
-                    // Else, listen to all events.
-                    eventtypes_bitmap_t eventToGet;
-                    eventToGet.set_all_events();
-
-                    if (!parseArgs(args, argCount, eventToGet))
-                    {
-                        NPN_SetException(this, strdup(ERROR_EVENT_NOT_FOUND));
-                        return INVOKERESULT_GENERIC_ERROR;
-                    }
-
-                    NPObject *listener = NPVARIANT_TO_OBJECT(args[0]);
-                    NPN_RetainObject(listener);
-
-                    EventListener *eventListener = new EventListener();
-                    eventListener->listener = listener;
-                    eventListener->id = copyNPVariant(args[1]);
-                    eventListener->eventMap = eventToGet;
-
-                    p_plugin->eventToCatch.add_event(eventToGet);
-
-                    p_plugin->eventListeners.push_back(eventListener);
-
-                    return INVOKERESULT_NO_ERROR;
-                }
-                return INVOKERESULT_NO_SUCH_METHOD;
-          case ID_event_removeListeners:
-              if (argCount == 0)
-              {
-                  VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
-                  p_plugin->eventListeners.clear();
-                  p_plugin->eventToCatch.clear();
-                  return INVOKERESULT_NO_ERROR;
-              }
-              return INVOKERESULT_NO_SUCH_METHOD;
-          default:
-              ;
-        }
-    }
-    return INVOKERESULT_GENERIC_ERROR;
-}
index 25e1adce69feebeb347b8080b96561716750d3d3..c6d8694b6d73ec8d84df7bb5627512d447f4920e 100644 (file)
@@ -38,8 +38,7 @@ protected:
     inputObj(NULL),
     playlistObj(NULL),
     subtitleObj(NULL),
-    videoObj(NULL),
-    eventObj(NULL) {};
+    videoObj(NULL) { }
 
     virtual ~LibvlcRootNPObject();
 
@@ -59,7 +58,6 @@ private:
     NPObject *playlistObj;
     NPObject *subtitleObj;
     NPObject *videoObj;
-    NPObject *eventObj;
 };
 
 class LibvlcAudioNPObject: public RuntimeNPObject
@@ -265,23 +263,3 @@ protected:
     InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result);
 };
 
-class LibvlcEventNPObject: public RuntimeNPObject
-{
-protected:
-    friend class RuntimeNPClass<LibvlcEventNPObject>;
-
-    LibvlcEventNPObject(NPP instance, const NPClass *aClass) :
-        RuntimeNPObject(instance, aClass) {};
-    virtual ~LibvlcEventNPObject() {};
-
-    static const int propertyCount;
-    static const NPUTF8 * const propertyNames[];
-
-    static const int methodCount;
-    static const NPUTF8 * const methodNames[];
-
-    InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result);
-
-    bool parseArgs(const NPVariant *args, uint32_t argCount,
-                   eventtypes_bitmap_t &eventToGet);
-};
index aa5010135cd18bf231aa24647a0588982281f9c0..0028b32be5364ff459fd6f05ef68533e26dbb23c 100644 (file)
@@ -36,7 +36,7 @@
 #include "control/npolibvlc.h"
 
 #include <ctype.h>
-#include <string>
+#include <pthread.h>
 
 /*****************************************************************************
  * VlcPlugin constructor and destructor
@@ -87,48 +87,156 @@ static bool boolValue(const char *value) {
              !strcasecmp(value, "yes") );
 }
 
-void eventAsync(void *param)
+
+void EventObj::deliver(NPP browser)
 {
-    VlcPlugin *plugin = (VlcPlugin*)param;
     NPVariant result;
-    NPVariant params[2];
+    NPVariant params[1];
 
-    pthread_mutex_lock(&plugin->mutex);
+    pthread_mutex_lock(&mutex);
 
-    for (int i = 0; i < plugin->eventList.size(); i++)
+    for( ev_l::iterator i=_elist.begin();i!=_elist.end();++i )
     {
-        for (int j = 0; j < plugin->eventListeners.size(); j++)
-        {
-            libvlc_event_type_t event = plugin->eventList[i];
+        libvlc_event_type_t event = *i;
+        STRINGZ_TO_NPVARIANT(libvlc_event_type_name(event), params[0]);
+
+        // Invalid events aren't supposed to be queued up.
+        // if( !have_event(event) ) continue;
 
-            if (plugin->eventListeners[j]->eventMap.have_event(event))
+        for( lr_l::iterator j=_llist.begin();j!=_llist.end();++j )
+        {
+            if (j->get(event))
             {
-                STRINGZ_TO_NPVARIANT(libvlc_event_type_name(event), params[0]);
-                params[1] = plugin->eventListeners[j]->id;
-                NPN_InvokeDefault(plugin->getBrowser(), plugin->eventListeners[j]->listener, params, 2, &result);
+                NPN_InvokeDefault(browser, j->listener(), params, 1, &result);
                 NPN_ReleaseVariantValue(&result);
             }
         }
     }
-    plugin->eventList.clear();
+    _elist.clear();
 
-    pthread_mutex_unlock(&plugin->mutex);
+    pthread_mutex_unlock(&mutex);
 }
 
-void event_callback(const libvlc_event_t* event, void *param)
+void VlcPlugin::eventAsync(void *param)
 {
     VlcPlugin *plugin = (VlcPlugin*)param;
+    plugin->events.deliver(plugin->getBrowser());
+}
 
-    pthread_mutex_lock(&plugin->mutex);
+void EventObj::callback(const libvlc_event_t* event)
+{
+    pthread_mutex_lock(&mutex);
 
-    if (plugin->eventToCatch.have_event(event->type))
-        plugin->eventList.push_back(event->type);
+    if( have_event(event->type) )
+        _elist.push_back(event->type);
 
-    pthread_mutex_unlock(&plugin->mutex);
+    pthread_mutex_unlock(&mutex);
+}
 
+void VlcPlugin::event_callback(const libvlc_event_t* event, void *param)
+{
+    VlcPlugin *plugin = (VlcPlugin*)param;
+    plugin->events.callback(event);
+#ifdef XP_UNIX
     NPN_PluginThreadAsyncCall(plugin->getBrowser(), eventAsync, plugin);
+#else
+    NPN_SetException(this, "NPN_PluginThreadAsyncCall not implemented yet.");
+#endif
+}
+
+inline EventObj::event_t EventObj::find_event(const char *s) const
+{
+    event_t i;
+    for(i=0;i<maxbit();++i)
+        if(!strcmp(s,libvlc_event_type_name(i)))
+            break;
+    return i;
 }
 
+bool EventObj::insert(const NPString &s, NPObject *l, bool b)
+{
+    event_t e = find_event(s.utf8characters);
+    if( e>=maxbit() )
+        return false;
+
+    if( !have_event(e) && !ask_for_event(e) )
+        return false;
+
+    lr_l::iterator i;
+    for(i=_llist.begin();i!=_llist.end();++i)
+        if(i->listener()==l && i->bubble()==b)
+            break;
+
+    if( i == _llist.end() ) {
+        _llist.push_back(Listener(e,l,b));
+    } else {
+        if( i->get(e) )
+            return false;
+        i->get(e);
+    }
+}
+
+
+bool EventObj::remove(const NPString &s, NPObject *l, bool b)
+{
+    event_t e = find_event(s.utf8characters);
+    if( e>=maxbit() || !get(e) )
+        return false;
+
+    bool any=false;
+    for(lr_l::iterator i=_llist.begin();i!=_llist.end();)
+    {
+        if(i->listener()!=l || i->bubble()!=b)
+            any|=i->get(e);
+        else
+        {
+            i->reset(e);
+            if(i->empty())
+            {
+                i=_llist.erase(i);
+                continue;
+            }
+        }
+        ++i;
+    }
+    if(!any)
+        unask_for_event(e);
+}
+
+
+void EventObj::hook_manager(libvlc_event_manager_t *em,
+                            libvlc_callback_t cb, void *udata)
+{
+    _em = em; _cb = cb; _ud = udata;
+    if( !_em )
+        return;
+    for(size_t i=0;i<maxbit();++i)
+        if(get(i))
+            libvlc_event_attach(_em, i, _cb, _ud);
+}
+
+void EventObj::unhook_manager()
+{
+    if( !_em )
+    return;
+    for(size_t i=0;i<maxbit();++i)
+        if(get(i))
+            libvlc_event_detach(_em, i, _cb, _ud);
+}
+
+
+bool EventObj::ask_for_event(event_t e)
+{
+    return _em?0==libvlc_event_attach(_em, e, _cb, _ud):false;
+}
+
+
+void EventObj::unask_for_event(event_t e)
+{
+    if(_em) libvlc_event_detach(_em, e, _cb, _ud);
+}
+
+
 NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
 {
     /* prepare VLC command line */
@@ -302,7 +410,7 @@ NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
     /* new APIs */
     p_scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
 
-    if (pthread_mutex_init(&mutex, NULL) != 0)
+    if( !events.init() )
         return NPERR_GENERIC_ERROR;
 
     return NPERR_NO_ERROR;
@@ -315,20 +423,14 @@ VlcPlugin::~VlcPlugin()
     free(psz_text);
 
     if( libvlc_media_player )
+    {
+        events.unhook_manager();
         libvlc_media_player_release( libvlc_media_player );
+    }
     if( libvlc_media_list )
         libvlc_media_list_release( libvlc_media_list );
     if( libvlc_instance )
         libvlc_release(libvlc_instance);
-    
-    for (int i = 0; i < eventListeners.size(); i++)
-    {
-        NPN_ReleaseObject(eventListeners[i]->listener);
-        NPN_ReleaseVariantValue(&(eventListeners[i]->id));
-        delete eventListeners[i];
-    }
-
-    pthread_mutex_destroy(&mutex);
 }
 
 /*****************************************************************************
@@ -391,7 +493,6 @@ int VlcPlugin::playlist_add_extended_untrusted( const char *mrl, const char *nam
 bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
 {
     libvlc_media_t *p_m = NULL;
-    libvlc_event_manager_t *eventManager = NULL;
 
     libvlc_media_list_lock(libvlc_media_list);
 
@@ -410,6 +511,7 @@ bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
 
     if( libvlc_media_player )
     {
+        events.unhook_manager();
         libvlc_media_player_release( libvlc_media_player );
         libvlc_media_player = NULL;
     }
@@ -418,25 +520,9 @@ bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
     if( libvlc_media_player )
     {
         set_player_window();
-
-        // Registers the events we're interested in.
-        eventManager = libvlc_media_player_event_manager(libvlc_media_player, ex);
-
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerOpening, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerStopped, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerPaused, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerForward, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerBackward, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerTitleChanged, event_callback, this, ex);
-        libvlc_event_attach(eventManager, libvlc_MediaPlayerSnapshotTaken, event_callback, this, ex);
-
+        events.hook_manager(
+                      libvlc_media_player_event_manager(libvlc_media_player),
+                      event_callback, this);
     }
 
     libvlc_media_release( p_m );
index 7cc0519641464e530bdd93c797c14b54a88a6dc5..950df74d1af4f9381f767bcf52fd67bb41ffe40f 100644 (file)
 #define __VLCPLUGIN_H__
 
 #include <vlc/vlc.h>
+#include <pthread.h>
 #include <npapi.h>
 #include <vector>
+
 #include "control/nporuntime.h"
 
 #if !defined(XP_MACOSX) && !defined(XP_UNIX) && !defined(XP_WIN)
@@ -90,11 +92,7 @@ private:
     enum { bmax=M, bpu=1<<shift, mask=bpu-1, units=(bmax+bpu-1)/bpu };
     bitu_t bits[units];
 public:
-    bool get(size_t idx) const
-    {
-        return bits[idx>>shift]&(1<<(idx&mask));
-    }
-
+    bool get(size_t idx) const { return bits[idx>>shift]&(1<<(idx&mask)); }
     void set(size_t idx)       { bits[idx>>shift]|=  1<<(idx&mask);  }
     void reset(size_t idx)     { bits[idx>>shift]&=~(1<<(idx&mask)); }
     void toggle(size_t idx)    { bits[idx>>shift]^=  1<<(idx&mask);  }
@@ -102,86 +100,63 @@ public:
     void clear()               { memset(bits,0,sizeof(bits)); }
     bitmap() { clear(); }
     ~bitmap() { }
+    bool empty() const { // naive invert() will break this
+        for(size_t i=0;i<units;++i)
+            if(bits[i]) return false;
+        return true;
+    }
 };
 
-typedef bitmap<libvlc_num_event_types> parent;
+typedef bitmap<libvlc_num_event_types> eventtypes_bitmap_t;
 
-class eventtypes_bitmap_t: private bitmap<libvlc_num_event_types> {
+
+class EventObj: private eventtypes_bitmap_t
+{
 private:
     typedef libvlc_event_type_t event_t;
-    event_t find_event(const char *s) const
-    {
-        event_t i;
-        for(i=0;i<maxbit();++i)
-            if(!strcmp(s,libvlc_event_type_name(i)))
-                break;
-        return i;
-    }
-public:
-    bool add_event(const eventtypes_bitmap_t &eventBitmap)
-    {
-        event_t i;
-        for(i=0;i<maxbit();++i)
-            if (eventBitmap.have_event(i))
-                set(i);
-    }
-    bool add_event(const char *s)
-    {
-        if (!strcmp(s, "all"))
-        {
-            set_all_events();
-            return true;
-        }
-        if (!strcmp(s, "none"))
-        {
-            clear();
-            return true;
-        }
+    bool have_event(event_t e) const { return e<maxbit()?get(e):false; }
 
-        event_t event = find_event(s);
-        bool b = event<maxbit();
-        if(b) set(event);
-        return b;
-    }
-    bool del_event(const char *s)
-    {
-        event_t event=find_event(s);
-        bool b=event<maxbit();
-        if(b) reset(event);
-        return b;
-    }
-    bool have_event(libvlc_event_type_t event) const
-    {
-        return event<maxbit()?get(event):false;
-    }
-    void clear()
+    class Listener: public eventtypes_bitmap_t
     {
-        parent::clear();
-    }
-    void set_all_events()
-    {
-        event_t i;
-        for(i=0;i<maxbit();++i)
-            set(i);
-    }
-};
+    public:
+        Listener(event_t e,NPObject *o,bool b): _l(o), _b(b)
+            { NPN_RetainObject(o); set(e); }
+        Listener(): _l(NULL), _b(false) { }
+        ~Listener() { if(_l) NPN_ReleaseObject(_l); }
+        NPObject *listener() const { return _l; }
+        bool bubble() const { return _b; }
+    private:
+        NPObject *_l;
+        bool _b;
+    };
+
+    libvlc_event_manager_t *_em;
+    libvlc_callback_t _cb;
+    void *_ud;
+public:
+    EventObj(): _em(NULL)  { /* deferred to init() */ }
+    bool init() { return pthread_mutex_init(&mutex, NULL) == 0; }
+    ~EventObj() { pthread_mutex_destroy(&mutex); }
+
+    void deliver(NPP browser);
+    void callback(const libvlc_event_t*);
+    bool insert(const NPString &, NPObject *, bool);
+    bool remove(const NPString &, NPObject *, bool);
+    void unhook_manager();
+    void hook_manager(libvlc_event_manager_t *,libvlc_callback_t, void *);
+private:
+    event_t find_event(const char *s) const;
+    typedef std::vector<Listener> lr_l;
+    typedef std::vector<libvlc_event_type_t> ev_l;
+    lr_l _llist;
+    ev_l _elist;
 
+    pthread_mutex_t mutex;
 
-// Structure used to represent an EventListener.
-// It contains the listener object that will be invoked,
-// An Id given by the addEventListener function and sent
-// when invoking the listener. Can be anything or nothing.
-// The profile associated with the listener used to invoke
-// the listener only to some events.
-typedef struct s_EventListener
-{
-    NPObject *listener;
-    NPVariant id;
-    eventtypes_bitmap_t eventMap;
-    
-} EventListener;
+    bool ask_for_event(event_t e);
+    void unask_for_event(event_t e);
+};
 
-void event_callback(const libvlc_event_t* event, void *param);
 
 class VlcPlugin
 {
@@ -302,14 +277,9 @@ public:
     bool  player_has_vout( libvlc_exception_t * );
 
 
-    // Events related members
-    std::vector<EventListener*> eventListeners; // List of registered listerners.
-    std::vector<libvlc_event_type_t> eventList; // List of event sent by VLC that must be returned to JS.
-    eventtypes_bitmap_t eventToCatch;
-    pthread_mutex_t mutex;
-
     static bool canUseEventListener();
 
+    EventObj events;
 private:
     bool playlist_select(int,libvlc_exception_t *);
     void set_player_window();
@@ -346,6 +316,9 @@ private:
 
     int i_last_position;
 #endif
+
+    static void eventAsync(void *);
+    static void event_callback(const libvlc_event_t *, void *);
 };
 
 /*******************************************************************************