X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Flua%2Fextension.c;h=498f50c9641b0b7b8a10366422f6869f644f37cb;hb=e20a107d1aae63efe536c863e9e9d4692da86e45;hp=2a6f4041ca055039725b13302a80a1c4d9e6cfd5;hpb=6db774279e14c3a8315b70f80dc79cd18d7d3bf3;p=vlc diff --git a/modules/misc/lua/extension.c b/modules/misc/lua/extension.c index 2a6f4041ca..498f50c964 100644 --- a/modules/misc/lua/extension.c +++ b/modules/misc/lua/extension.c @@ -43,18 +43,20 @@ static const luaL_Reg p_reg[] = #define EXT_TRIGGER_ONLY (1 << 1) ///< Hook: trigger. Not activable #define EXT_INPUT_LISTENER (1 << 2) ///< Hook: input_changed #define EXT_META_LISTENER (1 << 3) ///< Hook: meta_changed +#define EXT_PLAYING_LISTENER (1 << 4) ///< Hook: status_changed const char* const ppsz_capabilities[] = { "menu", "trigger", "input-listener", "meta-listener", + "playing-listener", NULL }; static int ScanExtensions( extensions_manager_t *p_this ); static int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script, - lua_State *L, void *pb_continue ); + void *pb_continue ); static int Control( extensions_manager_t *, int, va_list ); static int GetMenuEntries( extensions_manager_t *p_mgr, extension_t *p_ext, char ***pppsz_titles, uint16_t **ppi_ids ); @@ -99,15 +101,6 @@ int Open_Extension( vlc_object_t *p_this ) vlc_mutex_init( &p_mgr->lock ); vlc_mutex_init( &p_mgr->p_sys->lock ); - /* Initialise Lua state structure */ - lua_State *L = GetLuaState( p_mgr, NULL ); - if( !L ) - { - free( p_sys ); - return VLC_EGENERIC; - } - p_sys->L = L; - /* Scan available Lua Extensions */ if( ScanExtensions( p_mgr ) != VLC_SUCCESS ) { @@ -115,9 +108,6 @@ int Open_Extension( vlc_object_t *p_this ) return VLC_EGENERIC; } - lua_close( L ); - p_sys->L = NULL; - // Create the dialog-event variable var_Create( p_this, "dialog-event", VLC_VAR_ADDRESS ); var_AddCallback( p_this, "dialog-event", @@ -153,9 +143,6 @@ void Close_Extension( vlc_object_t *p_this ) msg_Dbg( p_mgr, "All extensions are now deactivated" ); ARRAY_RESET( p_mgr->p_sys->activated_extensions ); - if( p_mgr->p_sys && p_mgr->p_sys->L ) - lua_close( p_mgr->p_sys->L ); - vlc_mutex_destroy( &p_mgr->lock ); vlc_mutex_destroy( &p_mgr->p_sys->lock ); free( p_mgr->p_sys ); @@ -199,7 +186,7 @@ static int ScanExtensions( extensions_manager_t *p_mgr ) vlclua_scripts_batch_execute( VLC_OBJECT( p_mgr ), "extensions", &ScanLuaCallback, - p_mgr->p_sys->L, &b_true ); + &b_true ); if( !i_ret ) return VLC_EGENERIC; @@ -207,6 +194,18 @@ static int ScanExtensions( extensions_manager_t *p_mgr ) return VLC_SUCCESS; } +/** + * Dummy Lua function: does nothing + * @note This function can be used to replace "require" while scanning for + * extensions + * Even the built-in libraries are not loaded when calling descriptor() + **/ +static int vlclua_dummy_require( lua_State *L ) +{ + (void) L; + return 0; +} + /** * Batch scan all Lua files in folder "extensions": callback * @param p_this This extensions_manager_t object @@ -215,7 +214,7 @@ static int ScanExtensions( extensions_manager_t *p_mgr ) * @param pb_continue bool* that indicates whether to continue batch or not **/ int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script, - lua_State *L, void *pb_continue ) + void *pb_continue ) { extensions_manager_t *p_mgr = ( extensions_manager_t* ) p_this; bool b_ok = false; @@ -249,7 +248,11 @@ int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script, vlc_mutex_init( &p_ext->p_sys->running_lock ); vlc_cond_init( &p_ext->p_sys->wait ); - /* Load and run the script(s) */ + /* Prepare Lua state */ + lua_State *L = luaL_newstate(); + lua_register( L, "require", &vlclua_dummy_require ); + + /* Let's run it */ if( luaL_dofile( L, psz_script ) ) { msg_Warn( p_mgr, "Error loading script %s: %s", psz_script, @@ -263,14 +266,14 @@ int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script, if( !lua_isfunction( L, -1 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function descriptor() not found", psz_script ); goto exit; } if( lua_pcall( L, 0, 1, 0 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function descriptor(): %s", psz_script, lua_tostring( L, lua_gettop( L ) ) ); goto exit; @@ -339,61 +342,31 @@ int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script, /* Get author */ lua_getfield( L, -1, "author" ); if( lua_isstring( L, -1 ) ) - { - p_ext->psz_author = strdup( luaL_checkstring( L, -1 ) ); - } - else - { - p_ext->psz_author = NULL; - } + p_ext->psz_author = strdup( luaL_optstring( L, -1, NULL ) ); lua_pop( L, 1 ); /* Get description */ lua_getfield( L, -1, "description" ); if( lua_isstring( L, -1 ) ) - { - p_ext->psz_description = strdup( luaL_checkstring( L, -1 ) ); - } - else - { - p_ext->psz_description = NULL; - } + p_ext->psz_description = strdup( luaL_optstring( L, -1, NULL ) ); lua_pop( L, 1 ); /* Get short description */ lua_getfield( L, -1, "shortdesc" ); if( lua_isstring( L, -1 ) ) - { - p_ext->psz_shortdescription = strdup( luaL_checkstring( L, -1 ) ); - } - else - { - p_ext->psz_shortdescription = NULL; - } + p_ext->psz_shortdescription = strdup( luaL_optstring( L, -1, NULL ) ); lua_pop( L, 1 ); /* Get URL */ lua_getfield( L, -1, "url" ); if( lua_isstring( L, -1 ) ) - { - p_ext->psz_url = strdup( luaL_checkstring( L, -1 ) ); - } - else - { - p_ext->psz_url = NULL; - } + p_ext->psz_url = strdup( luaL_optstring( L, -1, NULL ) ); lua_pop( L, 1 ); /* Get version */ lua_getfield( L, -1, "version" ); if( lua_isstring( L, -1 ) ) - { - p_ext->psz_version = strdup( luaL_checkstring( L, -1 ) ); - } - else - { - p_ext->psz_version = NULL; - } + p_ext->psz_version = strdup( luaL_optstring( L, -1, NULL ) ); lua_pop( L, 1 ); } else @@ -414,6 +387,7 @@ int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script, b_ok = true; exit: + lua_close( L ); if( !b_ok ) { free( p_ext->psz_name ); @@ -542,7 +516,18 @@ static int Control( extensions_manager_t *p_mgr, int i_control, va_list args ) UnlockExtension( p_ext ); break; } - + case EXTENSION_PLAYING_CHANGED: + { + extension_t *p_ext; + p_ext = ( extension_t* ) va_arg( args, extension_t* ); + assert( p_ext->psz_name != NULL ); + i = ( int ) va_arg( args, int ); + if( p_ext->p_sys->i_capabilities & EXT_PLAYING_LISTENER ) + { + PushCommand( p_ext, CMD_PLAYING_CHANGED, i ); + } + break; + } default: msg_Warn( p_mgr, "Control '%d' not yet implemented in Extension", i_control ); @@ -555,7 +540,7 @@ static int Control( extensions_manager_t *p_mgr, int i_control, va_list args ) int lua_ExtensionActivate( extensions_manager_t *p_mgr, extension_t *p_ext ) { assert( p_mgr != NULL && p_ext != NULL ); - return lua_ExecuteFunction( p_mgr, p_ext, "activate" ); + return lua_ExecuteFunction( p_mgr, p_ext, "activate", LUA_END ); } int lua_ExtensionDeactivate( extensions_manager_t *p_mgr, extension_t *p_ext ) @@ -577,7 +562,7 @@ int lua_ExtensionDeactivate( extensions_manager_t *p_mgr, extension_t *p_ext ) vlc_object_release( p_ext->p_sys->p_input ); } - int i_ret = lua_ExecuteFunction( p_mgr, p_ext, "deactivate" ); + int i_ret = lua_ExecuteFunction( p_mgr, p_ext, "deactivate", LUA_END ); /* Clear Lua State */ lua_close( p_ext->p_sys->L ); @@ -593,7 +578,10 @@ int lua_ExtensionWidgetClick( extensions_manager_t *p_mgr, if( !p_ext->p_sys->L ) return VLC_SUCCESS; - return lua_ExecuteFunction( p_mgr, p_ext, (const char*) p_widget->p_sys ); + lua_State *L = GetLuaState( p_mgr, p_ext ); + lua_pushlightuserdata( L, p_widget ); + lua_gettable( L, LUA_REGISTRYINDEX ); + return lua_ExecuteFunction( p_mgr, p_ext, NULL, LUA_END ); } @@ -602,7 +590,7 @@ int lua_ExtensionWidgetClick( extensions_manager_t *p_mgr, * @param p_mgr * @param p_ext * @param pppsz_titles Pointer to NULL. All strings must be freed by the caller - * @param ppi_ids Pointer to NULL. Must be feed by the caller. + * @param ppi_ids Pointer to NULL. Must be freed by the caller. * @note This function is allowed to run in the UI thread. This means * that it MUST respond very fast. * @todo Remove the menu() hook and provide a new function vlc.set_menu() @@ -638,14 +626,14 @@ static int GetMenuEntries( extensions_manager_t *p_mgr, extension_t *p_ext, if( !lua_isfunction( L, -1 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function menu() not found", p_ext->psz_name ); goto exit; } if( lua_pcall( L, 0, 1, 0 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function menu(): %s", p_ext->psz_name, lua_tostring( L, lua_gettop( L ) ) ); goto exit; @@ -719,16 +707,13 @@ static lua_State* GetLuaState( extensions_manager_t *p_mgr, msg_Err( p_mgr, "Could not create new Lua State" ); return NULL; } + vlclua_set_this( L, p_mgr ); + vlclua_extension_set( L, p_ext ); + luaL_openlibs( L ); luaL_register( L, "vlc", p_reg ); luaopen_msg( L ); - lua_pushlightuserdata( L, p_mgr ); - lua_setfield( L, -2, "private" ); - - lua_pushlightuserdata( L, p_ext ); - lua_setfield( L, -2, "extension" ); - if( p_ext ) { /* Load more libraries */ @@ -736,6 +721,7 @@ static lua_State* GetLuaState( extensions_manager_t *p_mgr, luaopen_config( L ); luaopen_dialog( L, p_ext ); luaopen_input( L ); + luaopen_md5( L ); luaopen_msg( L ); luaopen_misc( L ); luaopen_net( L ); @@ -749,12 +735,20 @@ static lua_State* GetLuaState( extensions_manager_t *p_mgr, luaopen_video( L ); luaopen_vlm( L ); luaopen_volume( L ); + luaopen_xml( L ); /* Register extension specific functions */ lua_getglobal( L, "vlc" ); lua_pushcfunction( L, vlclua_extension_deactivate ); lua_setfield( L, -2, "deactivate" ); + /* Setup the module search path */ + if( vlclua_add_modules_path( p_mgr, L, p_ext->psz_name ) ) + { + msg_Warn( p_mgr, "Error while setting the module search path for %s", p_ext->psz_name ); + return NULL; + } + /* Load and run the script(s) */ if( luaL_dofile( L, p_ext->psz_name ) != 0 ) { @@ -767,44 +761,70 @@ static lua_State* GetLuaState( extensions_manager_t *p_mgr, p_ext->p_sys->L = L; } } -#ifndef NDEBUG - else - { - msg_Dbg( p_mgr, "Reusing old Lua state for extension '%s'", - p_ext->psz_name ); - } -#endif return L; } +int lua_ExecuteFunction( extensions_manager_t *p_mgr, extension_t *p_ext, + const char *psz_function, ... ) +{ + va_list args; + va_start( args, psz_function ); + int i_ret = lua_ExecuteFunctionVa( p_mgr, p_ext, psz_function, args ); + va_end( args ); + return i_ret; +} + /** * Execute a function in a Lua script + * @param psz_function Name of global function to execute. If NULL, assume + * that the function object is already on top of the + * stack. * @return < 0 in case of failure, >= 0 in case of success * @note It's better to call this function from a dedicated thread * (see extension_thread.c) **/ -int lua_ExecuteFunction( extensions_manager_t *p_mgr, - extension_t *p_ext, - const char *psz_function ) +int lua_ExecuteFunctionVa( extensions_manager_t *p_mgr, extension_t *p_ext, + const char *psz_function, va_list args ) { int i_ret = VLC_EGENERIC; + int i_args = 0; assert( p_mgr != NULL ); assert( p_ext != NULL ); lua_State *L = GetLuaState( p_mgr, p_ext ); - lua_getglobal( L, psz_function ); + if( psz_function ) + lua_getglobal( L, psz_function ); if( !lua_isfunction( L, -1 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function %s() not found", p_ext->psz_name, psz_function ); goto exit; } - if( lua_pcall( L, 0, 1, 0 ) ) + lua_datatype_e type = LUA_END; + while( ( type = va_arg( args, int ) ) != LUA_END ) + { + if( type == LUA_NUM ) + { + lua_pushnumber( L , ( int ) va_arg( args, int ) ); + } + else if( type == LUA_TEXT ) + { + lua_pushstring( L , ( char * ) va_arg( args, char* ) ); + } + else + { + msg_Warn( p_mgr, "Undefined argument type %d to lua function %s" + "from script %s", type, psz_function, p_ext->psz_name ); + goto exit; + } + i_args ++; + } + if( lua_pcall( L, i_args, 1, 0 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function %s(): %s", p_ext->psz_name, psz_function, lua_tostring( L, lua_gettop( L ) ) ); goto exit; @@ -813,6 +833,7 @@ int lua_ExecuteFunction( extensions_manager_t *p_mgr, i_ret = lua_DialogFlush( L ); exit: return i_ret; + } static inline int TriggerMenu( extension_t *p_ext, int i_id ) @@ -834,7 +855,7 @@ int lua_ExtensionTriggerMenu( extensions_manager_t *p_mgr, lua_getglobal( L, "trigger_menu" ); if( !lua_isfunction( L, -1 ) ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function trigger_menu() not found", p_ext->psz_name ); return VLC_EGENERIC; } @@ -844,7 +865,7 @@ int lua_ExtensionTriggerMenu( extensions_manager_t *p_mgr, if( lua_pcall( L, 1, 1, 0 ) != 0 ) { - msg_Warn( p_mgr, "Error while runing script %s, " + msg_Warn( p_mgr, "Error while running script %s, " "function trigger_menu(): %s", p_ext->psz_name, lua_tostring( L, lua_gettop( L ) ) ); return VLC_EGENERIC; @@ -868,7 +889,7 @@ int lua_ExtensionTriggerMenu( extensions_manager_t *p_mgr, static int TriggerExtension( extensions_manager_t *p_mgr, extension_t *p_ext ) { - int i_ret = lua_ExecuteFunction( p_mgr, p_ext, "trigger" ); + int i_ret = lua_ExecuteFunction( p_mgr, p_ext, "trigger", LUA_END ); /* Close lua state for trigger-only extensions */ if( p_ext->p_sys->L ) @@ -878,17 +899,27 @@ static int TriggerExtension( extensions_manager_t *p_mgr, return i_ret; } +/** Set extension associated to the current script + * @param L current lua_State + * @param p_ext the extension + */ +void vlclua_extension_set( lua_State *L, extension_t *p_ext ) +{ + lua_pushlightuserdata( L, vlclua_extension_set ); + lua_pushlightuserdata( L, p_ext ); + lua_rawset( L, LUA_REGISTRYINDEX ); +} + /** Retrieve extension associated to the current script * @param L current lua_State - * @return Lua userdata "vlc.extension" + * @return Extension pointer **/ extension_t *vlclua_extension_get( lua_State *L ) { - extension_t *p_ext = NULL; - lua_getglobal( L, "vlc" ); - lua_getfield( L, -1, "extension" ); - p_ext = (extension_t*) lua_topointer( L, lua_gettop( L ) ); - lua_pop( L, 2 ); + lua_pushlightuserdata( L, vlclua_extension_set ); + lua_rawget( L, LUA_REGISTRYINDEX ); + extension_t *p_ext = (extension_t*) lua_topointer( L, -1 ); + lua_pop( L, 1 ); return p_ext; } @@ -935,7 +966,7 @@ static int vlclua_extension_dialog_callback( vlc_object_t *p_this, { case EXTENSION_EVENT_CLICK: assert( p_widget != NULL ); - PushCommand( p_ext, CMD_CLICK, p_widget ); + PushCommandUnique( p_ext, CMD_CLICK, p_widget ); break; case EXTENSION_EVENT_CLOSE: PushCommandUnique( p_ext, CMD_CLOSE );