#include "assert.h"
#include <vlc_input.h>
+#include <vlc_events.h>
/* Functions to register */
static const luaL_Reg p_reg[] =
* Extensions capabilities
* Note: #define and ppsz_capabilities must be in sync
*/
-#define EXT_HAS_MENU (1 << 0)
-#define EXT_TRIGGER_ONLY (1 << 1)
+#define EXT_HAS_MENU (1 << 0) ///< Hook: menu
+#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
const char* const ppsz_capabilities[] = {
"menu",
"trigger",
+ "input-listener",
+ "meta-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_value_t newval,
void *p_data );
+/* Input item callback: vlc_InputItemMetaChanged */
+static void inputItemMetaChanged( const vlc_event_t *p_event,
+ void *data );
+
/**
* Module entry-point
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",
FOREACH_ARRAY( p_ext, p_mgr->p_sys->activated_extensions )
{
if( !p_ext ) break;
+ msg_Dbg( p_mgr, "Deactivating '%s'", p_ext->psz_title );
Deactivate( p_mgr, p_ext );
WaitForDeactivation( p_ext );
}
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;
* @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_cond_init( &p_ext->p_sys->wait );
/* Load and run the script(s) */
+ lua_State *L = luaL_newstate();
if( luaL_dofile( L, psz_script ) )
{
msg_Warn( p_mgr, "Error loading script %s: %s", psz_script,
}
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;
+ }
+ lua_pop( L, 1 );
+
/* Get URL */
lua_getfield( L, -1, "url" );
if( lua_isstring( L, -1 ) )
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 );
p_ext = ( extension_t* ) va_arg( args, extension_t* );
input_thread_t *p_input = va_arg( args, struct input_thread_t * );
- bool ok = LockExtension(p_ext);
- if (!ok)
+ if( !LockExtension( p_ext ) )
return VLC_EGENERIC;
+
+ // Change input
input_thread_t *old = p_ext->p_sys->p_input;
- if (old)
- vlc_object_release(old);
- p_ext->p_sys->p_input = p_input ? vlc_object_hold(p_input) : p_input;
- UnlockExtension(p_ext);
+ input_item_t *p_item;
+ if( old )
+ {
+ // Untrack meta fetched events
+ if( p_ext->p_sys->i_capabilities & EXT_META_LISTENER )
+ {
+ p_item = input_GetItem( old );
+ vlc_event_detach( &p_item->event_manager,
+ vlc_InputItemMetaChanged,
+ inputItemMetaChanged,
+ p_ext );
+ vlc_gc_decref( p_item );
+ }
+ vlc_object_release( old );
+ }
- return VLC_SUCCESS;
+ p_ext->p_sys->p_input = p_input ? vlc_object_hold( p_input )
+ : p_input;
+
+ // Tell the script the input changed
+ if( p_ext->p_sys->i_capabilities & EXT_INPUT_LISTENER )
+ {
+ PushCommandUnique( p_ext, CMD_SET_INPUT );
+ }
+
+ // Track meta fetched events
+ if( p_ext->p_sys->p_input &&
+ p_ext->p_sys->i_capabilities & EXT_META_LISTENER )
+ {
+ p_item = input_GetItem( p_ext->p_sys->p_input );
+ vlc_gc_incref( p_item );
+ vlc_event_attach( &p_item->event_manager,
+ vlc_InputItemMetaChanged,
+ inputItemMetaChanged,
+ p_ext );
+ }
+
+ UnlockExtension( p_ext );
+ break;
}
+
default:
- msg_Err( p_mgr, "Control '%d' not yet implemented in Extension",
- i_control );
+ msg_Warn( p_mgr, "Control '%d' not yet implemented in Extension",
+ i_control );
return VLC_EGENERIC;
}
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 )
if( !p_ext->p_sys->L )
return VLC_SUCCESS;
- int i_ret = lua_ExecuteFunction( p_mgr, p_ext, "deactivate" );
+ // Unset and release input objects
+ if( p_ext->p_sys->p_input )
+ {
+ if( p_ext->p_sys->i_capabilities & EXT_META_LISTENER )
+ {
+ // Release item
+ input_item_t *p_item = input_GetItem( p_ext->p_sys->p_input );
+ vlc_gc_decref( p_item );
+ }
+ vlc_object_release( p_ext->p_sys->p_input );
+ }
+
+ 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 );
+ return lua_ExecuteFunction( p_mgr, p_ext, (const char*) p_widget->p_sys, LUA_END );
}
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 )
{
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
* @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 );
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, "
"function %s(): %s", p_ext->psz_name, psz_function,
goto exit;
}
- i_ret = VLC_SUCCESS;
+ i_ret = lua_DialogFlush( L );
exit:
return i_ret;
+
}
static inline int TriggerMenu( extension_t *p_ext, int i_id )
return VLC_EGENERIC;
}
+ i_ret = lua_DialogFlush( L );
if( i_ret < VLC_SUCCESS )
{
msg_Dbg( p_mgr, "Something went wrong in %s (%s:%d)",
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 )
PushCommand( p_ext, CMD_CLICK, p_widget );
break;
case EXTENSION_EVENT_CLOSE:
- PushCommand( p_ext, CMD_CLOSE );
+ PushCommandUnique( p_ext, CMD_CLOSE );
break;
default:
msg_Dbg( p_this, "Received unknown UI event %d, discarded",
return VLC_SUCCESS;
}
+/** Callback on vlc_InputItemMetaChanged event
+ **/
+static void inputItemMetaChanged( const vlc_event_t *p_event,
+ void *data )
+{
+ assert( p_event && p_event->type == vlc_InputItemMetaChanged );
+
+ extension_t *p_ext = ( extension_t* ) data;
+ assert( p_ext != NULL );
+
+ PushCommandUnique( p_ext, CMD_UPDATE_META );
+}
+
/* Lock this extension. Can fail. */
bool LockExtension( extension_t *p_ext )
{