#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 );
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 )
{
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",
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 );
lua_close( p_ext->p_sys->L );
free( p_ext->psz_name );
free( p_ext->psz_title );
+ free( p_ext->psz_author );
+ free( p_ext->psz_description );
+ free( p_ext->psz_shortdescription );
+ free( p_ext->psz_url );
+ free( p_ext->psz_version );
vlc_mutex_destroy( &p_ext->p_sys->running_lock );
vlc_mutex_destroy( &p_ext->p_sys->command_lock );
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;
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
* @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;
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,
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;
/* 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_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
b_ok = true;
exit:
+ lua_close( L );
if( !b_ok )
{
free( p_ext->psz_name );
free( p_ext->psz_url );
free( p_ext->psz_author );
free( p_ext->psz_description );
+ free( p_ext->psz_shortdescription );
free( p_ext->psz_version );
vlc_mutex_destroy( &p_ext->p_sys->command_lock );
vlc_mutex_destroy( &p_ext->p_sys->running_lock );
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 );
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 )
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 );
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 );
}
* @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()
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;
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 */
luaopen_config( L );
luaopen_dialog( L, p_ext );
luaopen_input( L );
+ luaopen_md5( L );
luaopen_msg( L );
luaopen_misc( L );
luaopen_net( L );
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 )
{
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;
i_ret = lua_DialogFlush( L );
exit:
return i_ret;
+
}
static inline int TriggerMenu( extension_t *p_ext, int i_id )
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;
}
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;
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 )
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;
}
{
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 );