1 /*****************************************************************************
2 * extension_thread.c: Extensions Manager, Threads manager (no Lua here)
3 *****************************************************************************
4 * Copyright (C) 2009-2010 VideoLAN and authors
7 * Authors: Jean-Philippe André < jpeg # videolan.org >
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /* I don't want to include lua headers here */
25 typedef struct lua_State lua_State;
27 #include "extension.h"
32 extensions_manager_t *p_mgr;
37 static void* Run( void *data );
38 static void FreeCommands( struct command_t *command );
39 static int RemoveActivated( extensions_manager_t *p_mgr, extension_t *p_ext );
42 * Activate an extension
43 * @param p_mgr This manager
44 * @param p_ext Extension to activate
45 * @return The usual VLC return codes
47 int Activate( extensions_manager_t *p_mgr, extension_t *p_ext )
49 assert( p_ext != NULL );
51 struct extension_sys_t *p_sys = p_ext->p_sys;
52 assert( p_sys != NULL );
54 msg_Dbg( p_mgr, "Activating extension '%s'", p_ext->psz_title );
56 if( IsActivated( p_mgr, p_ext ) )
58 msg_Warn( p_mgr, "Extension is already activated!" );
62 /* Add this script to the activated extensions list */
63 vlc_mutex_lock( &p_mgr->p_sys->lock );
64 ARRAY_APPEND( p_mgr->p_sys->activated_extensions, p_ext );
65 vlc_mutex_unlock( &p_mgr->p_sys->lock );
67 /* Prepare first command */
68 p_sys->command = calloc( 1, sizeof( struct command_t ) );
71 p_sys->command->i_command = CMD_ACTIVATE; /* No params */
74 p_sys->b_exiting = false;
76 if( vlc_clone( &p_sys->thread, Run, p_ext, VLC_THREAD_PRIORITY_LOW )
79 p_sys->b_exiting = true;
80 // Note: Automatically deactivating the extension...
81 Deactivate( p_mgr, p_ext );
88 /** Look for an extension in the activated extensions list */
89 bool IsActivated( extensions_manager_t *p_mgr, extension_t *p_ext )
91 assert( p_ext != NULL );
92 vlc_mutex_lock( &p_mgr->p_sys->lock );
95 FOREACH_ARRAY( p_iter, p_mgr->p_sys->activated_extensions )
99 assert( p_iter->psz_name != NULL );
100 if( !strcmp( p_iter->psz_name, p_ext->psz_name ) )
102 vlc_mutex_unlock( &p_mgr->p_sys->lock );
108 vlc_mutex_unlock( &p_mgr->p_sys->lock );
112 /** Recursively drop and free commands starting from "command" */
113 static void FreeCommands( struct command_t *command )
115 if( !command ) return;
116 struct command_t *next = command->next;
117 switch( command->i_command )
121 case CMD_CLICK: // Arg1 must not be freed
124 case CMD_TRIGGERMENU:
125 free( command->data[0] ); // Arg1 is int*, to free
129 FreeCommands( next );
132 /** Deactivate this extension: pushes immediate command and drops queued */
133 int Deactivate( extensions_manager_t *p_mgr, extension_t *p_ext )
136 vlc_mutex_lock( &p_ext->p_sys->command_lock );
138 if( p_ext->p_sys->b_exiting )
140 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
144 /* Free the list of commands */
145 FreeCommands( p_ext->p_sys->command );
148 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
149 cmd->i_command = CMD_DEACTIVATE;
150 p_ext->p_sys->command = cmd;
152 vlc_cond_signal( &p_ext->p_sys->wait );
153 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
158 /** Remove an extension from the activated list */
159 static int RemoveActivated( extensions_manager_t *p_mgr, extension_t *p_ext )
161 if( p_mgr->p_sys->b_killed )
163 vlc_mutex_lock( &p_mgr->p_sys->lock );
167 FOREACH_ARRAY( p_iter, p_mgr->p_sys->activated_extensions )
175 assert( p_iter->psz_name != NULL );
176 if( !strcmp( p_iter->psz_name, p_ext->psz_name ) )
183 ARRAY_REMOVE( p_mgr->p_sys->activated_extensions, i_idx );
187 msg_Dbg( p_mgr, "Can't find extension '%s' in the activated list",
191 vlc_mutex_unlock( &p_mgr->p_sys->lock );
192 return (i_idx >= 0) ? VLC_SUCCESS : VLC_EGENERIC;
195 /** Wait for an extension to finish */
196 void WaitForDeactivation( extension_t *p_ext )
198 void *pointer = NULL;
199 vlc_cond_signal( &p_ext->p_sys->wait );
200 vlc_join( p_ext->p_sys->thread, &pointer );
203 /** Push a UI command */
204 int PushCommand( extension_t *p_ext,
208 vlc_mutex_lock( &p_ext->p_sys->command_lock );
211 va_start( args, i_command );
214 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
215 cmd->i_command = i_command;
219 cmd->data[0] = va_arg( args, void* );
222 // Nothing to do here
224 case CMD_TRIGGERMENU:
226 int *pi = malloc( sizeof( int ) );
230 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
233 *pi = va_arg( args, int );
238 msg_Dbg( p_ext->p_sys->p_mgr,
239 "Unknown command send to extension: %d", i_command );
245 /* Push command to the end of the queue */
246 struct command_t *last = p_ext->p_sys->command;
249 p_ext->p_sys->command = cmd;
253 while( last->next != NULL )
260 vlc_cond_signal( &p_ext->p_sys->wait );
261 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
266 static void* Run( void *data )
268 extension_t *p_ext = data;
269 extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
271 vlc_mutex_lock( &p_ext->p_sys->command_lock );
273 while( !p_ext->p_sys->b_exiting )
275 /* Pop command in front */
276 struct command_t *cmd = p_ext->p_sys->command;
279 p_ext->p_sys->command = cmd->next;
282 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
287 if( LockExtension( p_ext ) )
289 switch( cmd->i_command )
293 if( lua_ExecuteFunction( p_mgr, p_ext, "activate" ) < 0 )
295 msg_Dbg( p_mgr, "Could not activate extension!" );
296 Deactivate( p_mgr, p_ext );
303 msg_Dbg( p_mgr, "Deactivating '%s'", p_ext->psz_title );
304 if( lua_ExtensionDeactivate( p_mgr, p_ext ) < 0 )
306 msg_Warn( p_mgr, "Extension '%s' did not deactivate properly",
309 p_ext->p_sys->b_exiting = true;
310 RemoveActivated( p_mgr, p_ext );
316 lua_ExecuteFunction( p_mgr, p_ext, "close" );
322 extension_widget_t *p_widget = cmd->data[0];
324 msg_Dbg( p_mgr, "Clicking '%s': '%s'",
325 p_ext->psz_name, p_widget->psz_text );
326 if( !lua_ExtensionWidgetClick( p_mgr, p_ext, p_widget )
329 msg_Warn( p_mgr, "Could not translate click" );
334 case CMD_TRIGGERMENU:
336 int *pi_id = cmd->data[0];
338 msg_Dbg( p_mgr, "Trigger menu %d of '%s'",
339 *pi_id, p_ext->psz_name );
340 lua_ExtensionTriggerMenu( p_mgr, p_ext, *pi_id );
347 msg_Dbg( p_mgr, "Unknown command in extension command queue: %d",
352 UnlockExtension( p_ext );
356 vlc_mutex_lock( &p_ext->p_sys->command_lock );
357 if( !p_ext->p_sys->b_exiting && !p_ext->p_sys->command )
359 vlc_cond_wait( &p_ext->p_sys->wait, &p_ext->p_sys->command_lock );
363 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
364 msg_Dbg( p_mgr, "Extension thread ending..." );
366 // Note: At this point, the extension should be deactivated