** implementation of libvlc root object\r
*/\r
\r
-LibvlcRootNPObject::LibvlcRootNPObject(NPP instance, const NPClass *aClass) :\r
- RuntimeNPObject(instance, aClass)\r
-{\r
- audioObj = NPN_CreateObject(instance, RuntimeNPClass<LibvlcAudioNPObject>::getClass());\r
- inputObj = NPN_CreateObject(instance, RuntimeNPClass<LibvlcInputNPObject>::getClass());\r
- logObj = NPN_CreateObject(instance, RuntimeNPClass<LibvlcLogNPObject>::getClass());\r
- playlistObj = NPN_CreateObject(instance, RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());\r
- videoObj = NPN_CreateObject(instance,RuntimeNPClass<LibvlcVideoNPObject>::getClass());\r
-}\r
-\r
LibvlcRootNPObject::~LibvlcRootNPObject()\r
{\r
- NPN_ReleaseObject(audioObj);\r
- NPN_ReleaseObject(inputObj);\r
- NPN_ReleaseObject(logObj);\r
- NPN_ReleaseObject(playlistObj);\r
- NPN_ReleaseObject(videoObj);\r
+ /*\r
+ ** when plugin is destroyed, firefox takes upon itself to destroy all 'live' script objects\r
+ ** and ignores refcounting. Therefore we cannot safely assume that refcounting will control\r
+ ** lifespan of objects. Hence they are only lazily created on request, so that firefox can\r
+ ** take ownership, and are not released when plugin is being destroyed.\r
+ */\r
+ if( isValid() )\r
+ {\r
+ if( audioObj ) NPN_ReleaseObject(audioObj);\r
+ if( inputObj ) NPN_ReleaseObject(inputObj);\r
+ if( logObj ) NPN_ReleaseObject(logObj);\r
+ if( playlistObj ) NPN_ReleaseObject(playlistObj);\r
+ if( videoObj ) NPN_ReleaseObject(videoObj);\r
+ }\r
}\r
\r
const NPUTF8 * const LibvlcRootNPObject::propertyNames[] = \r
switch( index )\r
{\r
case ID_root_audio:\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( audioObj )\r
+ NPN_RetainObject(audioObj);\r
+ else\r
+ audioObj = NPN_CreateObject(_instance, RuntimeNPClass<LibvlcAudioNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(audioObj, result);\r
return INVOKERESULT_NO_ERROR;\r
case ID_root_input:\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( inputObj )\r
+ NPN_RetainObject(inputObj);\r
+ else\r
+ inputObj = NPN_CreateObject(_instance, RuntimeNPClass<LibvlcInputNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(inputObj, result);\r
return INVOKERESULT_NO_ERROR;\r
case ID_root_log:\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(logObj), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( logObj )\r
+ NPN_RetainObject(logObj);\r
+ else\r
+ logObj = NPN_CreateObject(_instance, RuntimeNPClass<LibvlcLogNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(logObj, result);\r
return INVOKERESULT_NO_ERROR;\r
case ID_root_playlist:\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( playlistObj )\r
+ NPN_RetainObject(playlistObj);\r
+ else\r
+ playlistObj = NPN_CreateObject(_instance, RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(playlistObj, result);\r
return INVOKERESULT_NO_ERROR;\r
case ID_root_video:\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( videoObj )\r
+ NPN_RetainObject(videoObj);\r
+ else\r
+ videoObj = NPN_CreateObject(_instance,RuntimeNPClass<LibvlcVideoNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(videoObj, result);\r
return INVOKERESULT_NO_ERROR;\r
case ID_root_VersionInfo:\r
{\r
*/\r
\r
\r
-LibvlcLogNPObject::LibvlcLogNPObject(NPP instance, const NPClass *aClass) :\r
- RuntimeNPObject(instance, aClass)\r
-{\r
- _p_vlcmessages = NPN_CreateObject(instance, RuntimeNPClass<LibvlcMessagesNPObject>::getClass());\r
-};\r
- \r
LibvlcLogNPObject::~LibvlcLogNPObject()\r
{\r
- NPN_ReleaseObject(_p_vlcmessages);\r
+ if( isValid() )\r
+ {\r
+ if( messagesObj ) NPN_ReleaseObject(messagesObj);\r
+ }\r
};\r
\r
const NPUTF8 * const LibvlcLogNPObject::propertyNames[] = \r
{\r
case ID_log_messages:\r
{\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(_p_vlcmessages), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( messagesObj )\r
+ NPN_RetainObject(messagesObj);\r
+ else\r
+ messagesObj = NPN_CreateObject(_instance, RuntimeNPClass<LibvlcMessagesNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(messagesObj, result);\r
return INVOKERESULT_NO_ERROR;\r
}\r
case ID_log_verbosity:\r
*/\r
\r
\r
-LibvlcPlaylistNPObject::LibvlcPlaylistNPObject(NPP instance, const NPClass *aClass) :\r
- RuntimeNPObject(instance, aClass)\r
-{\r
- _p_vlcplaylistitems = NPN_CreateObject(instance, RuntimeNPClass<LibvlcPlaylistItemsNPObject>::getClass());\r
-};\r
- \r
LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()\r
{\r
- NPN_ReleaseObject(_p_vlcplaylistitems);\r
+ if( isValid() )\r
+ {\r
+ if( playlistItemsObj ) NPN_ReleaseObject(playlistItemsObj);\r
+ }\r
};\r
\r
const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] = \r
}\r
case ID_playlist_items:\r
{\r
- OBJECT_TO_NPVARIANT(NPN_RetainObject(_p_vlcplaylistitems), result);\r
+ // create child object in lazyman fashion to avoid ownership problem with firefox\r
+ if( playlistItemsObj )\r
+ NPN_RetainObject(playlistItemsObj);\r
+ else\r
+ playlistItemsObj = NPN_CreateObject(_instance, RuntimeNPClass<LibvlcPlaylistItemsNPObject>::getClass());\r
+ OBJECT_TO_NPVARIANT(playlistItemsObj, result);\r
return INVOKERESULT_NO_ERROR;\r
}\r
default:\r
protected:\r
friend class RuntimeNPClass<LibvlcRootNPObject>;\r
\r
- LibvlcRootNPObject(NPP instance, const NPClass *aClass);\r
+ LibvlcRootNPObject(NPP instance, const NPClass *aClass) :\r
+ RuntimeNPObject(instance, aClass),\r
+ audioObj(NULL),\r
+ inputObj(NULL),\r
+ logObj(NULL),\r
+ playlistObj(NULL),\r
+ videoObj(NULL) {};\r
+\r
virtual ~LibvlcRootNPObject();\r
\r
static const int propertyCount;\r
protected:\r
friend class RuntimeNPClass<LibvlcLogNPObject>;\r
\r
- LibvlcLogNPObject(NPP instance, const NPClass *aClass);\r
+ LibvlcLogNPObject(NPP instance, const NPClass *aClass) :\r
+ RuntimeNPObject(instance, aClass),\r
+ messagesObj(NULL) {};\r
+\r
virtual ~LibvlcLogNPObject();\r
\r
static const int propertyCount;\r
static const NPUTF8 * const methodNames[];\r
\r
private:\r
- NPObject* _p_vlcmessages;\r
+ NPObject* messagesObj;\r
};\r
\r
class LibvlcPlaylistItemsNPObject: public RuntimeNPObject\r
protected:\r
friend class RuntimeNPClass<LibvlcPlaylistNPObject>;\r
\r
- LibvlcPlaylistNPObject(NPP instance, const NPClass *aClass);\r
+ LibvlcPlaylistNPObject(NPP instance, const NPClass *aClass) :\r
+ RuntimeNPObject(instance, aClass),\r
+ playlistItemsObj(NULL) {};\r
+ \r
virtual ~LibvlcPlaylistNPObject();\r
\r
static const int propertyCount;\r
void parseOptions(NPObject *obj, int *i_options, char*** ppsz_options);\r
\r
private:\r
- NPObject* _p_vlcplaylistitems;\r
+ NPObject* playlistItemsObj;\r
};\r
\r
class LibvlcVideoNPObject: public RuntimeNPObject\r
protected:
void *operator new(size_t n)
{
+ /*
+ ** Assume that browser has a smarter memory allocator
+ ** than plain old malloc() and use it instead.
+ */
return NPN_MemAlloc(n);
};
void operator delete(void *p)
{
- /*
- ** Some memory scribble happens occasionally on freed object
- ** when used on Firefox (MacOS X) and may cause crash, a leak
- ** sounds like the better option.
- */
- //NPN_MemFree(p);
+ NPN_MemFree(p);
+ };
+
+ bool isValid()
+ {
+ return _instance != NULL;
};
RuntimeNPObject(NPP instance, const NPClass *aClass) :
static bool RuntimeNPClassGetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
{
RuntimeNPObject *vObj = static_cast<RuntimeNPObject *>(npobj);
- if( vObj->_instance )
+ if( vObj->isValid() )
{
const RuntimeNPClass<T> *vClass = static_cast<RuntimeNPClass<T> *>(npobj->_class);
int index = vClass->indexOfProperty(name);
static bool RuntimeNPClassSetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
{
RuntimeNPObject *vObj = static_cast<RuntimeNPObject *>(npobj);
- if( vObj->_instance )
+ if( vObj->isValid() )
{
const RuntimeNPClass<T> *vClass = static_cast<RuntimeNPClass<T> *>(npobj->_class);
int index = vClass->indexOfProperty(name);
static bool RuntimeNPClassRemoveProperty(NPObject *npobj, NPIdentifier name)
{
RuntimeNPObject *vObj = static_cast<RuntimeNPObject *>(npobj);
- if( vObj->_instance )
+ if( vObj->isValid() )
{
const RuntimeNPClass<T> *vClass = static_cast<RuntimeNPClass<T> *>(npobj->_class);
int index = vClass->indexOfProperty(name);
NPVariant *result)
{
RuntimeNPObject *vObj = static_cast<RuntimeNPObject *>(npobj);
- if( vObj->_instance )
+ if( vObj->isValid() )
{
const RuntimeNPClass<T> *vClass = static_cast<RuntimeNPClass<T> *>(npobj->_class);
int index = vClass->indexOfMethod(name);
NPVariant *result)
{
RuntimeNPObject *vObj = static_cast<RuntimeNPObject *>(npobj);
- if( vObj->_instance )
+ if( vObj->isValid() )
{
return vObj->returnInvokeResult(vObj->invokeDefault(args, argCount, *result));
}