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 *****************************************************************************/
28 /* I don't want to include lua headers here */
29 typedef struct lua_State lua_State;
31 #include "extension.h"
36 extensions_manager_t *p_mgr;
41 static void* Run( void *data );
42 static void FreeCommands( struct command_t *command );
43 static int RemoveActivated( extensions_manager_t *p_mgr, extension_t *p_ext );
46 * Activate an extension
47 * @param p_mgr This manager
48 * @param p_ext Extension to activate
49 * @return The usual VLC return codes
51 int Activate( extensions_manager_t *p_mgr, extension_t *p_ext )
53 assert( p_ext != NULL );
55 struct extension_sys_t *p_sys = p_ext->p_sys;
56 assert( p_sys != NULL );
58 msg_Dbg( p_mgr, "Activating extension '%s'", p_ext->psz_title );
60 if( IsActivated( p_mgr, p_ext ) )
62 msg_Warn( p_mgr, "Extension is already activated!" );
66 /* Add this script to the activated extensions list */
67 vlc_mutex_lock( &p_mgr->p_sys->lock );
68 ARRAY_APPEND( p_mgr->p_sys->activated_extensions, p_ext );
69 vlc_mutex_unlock( &p_mgr->p_sys->lock );
71 /* Prepare first command */
72 p_sys->command = calloc( 1, sizeof( struct command_t ) );
75 p_sys->command->i_command = CMD_ACTIVATE; /* No params */
78 p_sys->b_exiting = false;
80 if( vlc_clone( &p_sys->thread, Run, p_ext, VLC_THREAD_PRIORITY_LOW )
83 p_sys->b_exiting = true;
84 // Note: Automatically deactivating the extension...
85 Deactivate( p_mgr, p_ext );
92 /** Look for an extension in the activated extensions list
93 * @todo FIXME Should be entered with the lock held
95 bool IsActivated( extensions_manager_t *p_mgr, extension_t *p_ext )
97 assert( p_ext != NULL );
98 vlc_mutex_lock( &p_mgr->p_sys->lock );
101 FOREACH_ARRAY( p_iter, p_mgr->p_sys->activated_extensions )
105 assert( p_iter->psz_name != NULL );
106 if( !strcmp( p_iter->psz_name, p_ext->psz_name ) )
108 vlc_mutex_unlock( &p_mgr->p_sys->lock );
114 vlc_mutex_unlock( &p_mgr->p_sys->lock );
118 /** Recursively drop and free commands starting from "command" */
119 static void FreeCommands( struct command_t *command )
121 if( !command ) return;
122 struct command_t *next = command->next;
123 switch( command->i_command )
127 case CMD_CLICK: // Arg1 must not be freed
130 case CMD_TRIGGERMENU:
131 case CMD_PLAYING_CHANGED:
132 free( command->data[0] ); // Arg1 is int*, to free
139 FreeCommands( next );
142 /** Deactivate this extension: pushes immediate command and drops queued */
143 int Deactivate( extensions_manager_t *p_mgr, extension_t *p_ext )
146 vlc_mutex_lock( &p_ext->p_sys->command_lock );
148 if( p_ext->p_sys->b_exiting )
150 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
154 if( p_ext->p_sys->progress )
156 // Extension is stuck, kill it now
157 dialog_ProgressDestroy( p_ext->p_sys->progress );
158 p_ext->p_sys->progress = NULL;
159 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
160 KillExtension( p_mgr, p_ext );
164 /* Free the list of commands */
165 if( p_ext->p_sys->command )
166 FreeCommands( p_ext->p_sys->command->next );
169 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
170 cmd->i_command = CMD_DEACTIVATE;
171 if( p_ext->p_sys->command )
172 p_ext->p_sys->command->next = cmd;
174 p_ext->p_sys->command = cmd;
176 vlc_cond_signal( &p_ext->p_sys->wait );
177 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
182 /** Remove an extension from the activated list */
183 static int RemoveActivated( extensions_manager_t *p_mgr, extension_t *p_ext )
185 if( p_mgr->p_sys->b_killed )
187 vlc_mutex_lock( &p_mgr->p_sys->lock );
191 FOREACH_ARRAY( p_iter, p_mgr->p_sys->activated_extensions )
199 assert( p_iter->psz_name != NULL );
200 if( !strcmp( p_iter->psz_name, p_ext->psz_name ) )
207 ARRAY_REMOVE( p_mgr->p_sys->activated_extensions, i_idx );
211 msg_Dbg( p_mgr, "Can't find extension '%s' in the activated list",
215 vlc_mutex_unlock( &p_mgr->p_sys->lock );
216 return (i_idx >= 0) ? VLC_SUCCESS : VLC_EGENERIC;
219 void KillExtension( extensions_manager_t *p_mgr, extension_t *p_ext )
221 /* Cancel thread if it seems stuck for a while */
222 msg_Dbg( p_mgr, "Killing extension now" );
223 vlc_cancel( p_ext->p_sys->thread );
224 lua_ExtensionDeactivate( p_mgr, p_ext );
225 p_ext->p_sys->b_exiting = true;
226 RemoveActivated( p_mgr, p_ext );
229 /** Push a UI command */
230 int __PushCommand( extension_t *p_ext, bool b_unique, command_type_e i_command,
233 vlc_mutex_lock( &p_ext->p_sys->command_lock );
236 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
237 cmd->i_command = i_command;
241 cmd->data[0] = va_arg( args, void* );
243 case CMD_TRIGGERMENU:
245 int *pi = malloc( sizeof( int ) );
249 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
252 *pi = va_arg( args, int );
256 case CMD_PLAYING_CHANGED:
258 int *pi = malloc( sizeof( int ) );
262 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
265 *pi = va_arg( args, int );
271 case CMD_UPDATE_META:
272 // Nothing to do here
275 msg_Dbg( p_ext->p_sys->p_mgr,
276 "Unknown command send to extension: %d", i_command );
280 /* Push command to the end of the queue */
281 struct command_t *last = p_ext->p_sys->command;
284 p_ext->p_sys->command = cmd;
289 while( last->next != NULL )
291 if( b_unique && last->i_command == i_command )
293 // Do not push this 'unique' command a second time
294 b_skip = !memcmp( last->data, cmd->data, sizeof( cmd->data ) );
312 vlc_cond_signal( &p_ext->p_sys->wait );
313 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
318 static void* Run( void *data )
320 extension_t *p_ext = data;
321 extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
323 vlc_mutex_lock( &p_ext->p_sys->command_lock );
324 mutex_cleanup_push( &p_ext->p_sys->command_lock );
326 while( !p_ext->p_sys->b_exiting )
328 struct command_t *cmd = p_ext->p_sys->command;
330 /* Pop command in front */
333 vlc_cond_wait( &p_ext->p_sys->wait, &p_ext->p_sys->command_lock );
336 p_ext->p_sys->command = cmd->next;
337 cmd->next = NULL; /* unlink command (for FreeCommands()) */
339 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
342 int cancel = vlc_savecancel();
343 if( LockExtension( p_ext ) )
345 switch( cmd->i_command )
349 if( lua_ExecuteFunction( p_mgr, p_ext, "activate", LUA_END ) < 0 )
351 msg_Err( p_mgr, "Could not activate extension!" );
352 Deactivate( p_mgr, p_ext );
359 msg_Dbg( p_mgr, "Deactivating '%s'", p_ext->psz_title );
360 if( lua_ExtensionDeactivate( p_mgr, p_ext ) < 0 )
362 msg_Warn( p_mgr, "Extension '%s' did not deactivate properly",
365 p_ext->p_sys->b_exiting = true;
366 RemoveActivated( p_mgr, p_ext );
372 lua_ExecuteFunction( p_mgr, p_ext, "close", LUA_END );
378 extension_widget_t *p_widget = cmd->data[0];
380 msg_Dbg( p_mgr, "Clicking '%s': '%s'",
381 p_ext->psz_name, p_widget->psz_text );
382 if( lua_ExtensionWidgetClick( p_mgr, p_ext, p_widget ) < 0 )
384 msg_Warn( p_mgr, "Could not translate click" );
389 case CMD_TRIGGERMENU:
391 int *pi_id = cmd->data[0];
393 msg_Dbg( p_mgr, "Trigger menu %d of '%s'",
394 *pi_id, p_ext->psz_name );
395 lua_ExtensionTriggerMenu( p_mgr, p_ext, *pi_id );
401 lua_ExecuteFunction( p_mgr, p_ext, "input_changed", LUA_END );
405 case CMD_UPDATE_META:
407 lua_ExecuteFunction( p_mgr, p_ext, "meta_changed", LUA_END );
411 case CMD_PLAYING_CHANGED:
413 lua_ExecuteFunction( p_mgr, p_ext, "playing_changed",
414 LUA_NUM, *((int *)cmd->data[0]), LUA_END );
420 msg_Dbg( p_mgr, "Unknown command in extension command queue: %d",
425 UnlockExtension( p_ext );
429 vlc_restorecancel( cancel );
430 vlc_mutex_lock( &p_ext->p_sys->command_lock );
434 msg_Dbg( p_mgr, "Extension thread end: '%s'", p_ext->psz_title );
436 // Note: At this point, the extension should be deactivated