lua extensions: use an enum and remove demuy declaration.
[vlc/asuraparaju-public.git] / modules / misc / lua / extension_thread.c
blob318eb748a9dd35e3b36bff9f1ca9fd4984df604e
1 /*****************************************************************************
2 * extension_thread.c: Extensions Manager, Threads manager (no Lua here)
3 *****************************************************************************
4 * Copyright (C) 2009-2010 VideoLAN and authors
5 * $Id$
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"
28 #include "assert.h"
30 struct thread_sys_t
32 extensions_manager_t *p_mgr;
33 extension_t *p_ext;
36 /** Thread Run */
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 );
41 /**
42 * Activate an extension
43 * @param p_mgr This manager
44 * @param p_ext Extension to activate
45 * @return The usual VLC return codes
46 **/
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!" );
59 return VLC_EGENERIC;
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 ) );
69 if( !p_sys->command )
70 return VLC_ENOMEM;
71 p_sys->command->i_command = CMD_ACTIVATE; /* No params */
73 /* Start thread */
74 p_sys->b_exiting = false;
76 if( vlc_clone( &p_sys->thread, Run, p_ext, VLC_THREAD_PRIORITY_LOW )
77 != VLC_SUCCESS )
79 p_sys->b_exiting = true;
80 // Note: Automatically deactivating the extension...
81 Deactivate( p_mgr, p_ext );
82 return VLC_ENOMEM;
85 return VLC_SUCCESS;
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 );
94 extension_t *p_iter;
95 FOREACH_ARRAY( p_iter, p_mgr->p_sys->activated_extensions )
97 if( !p_iter )
98 break;
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 );
103 return true;
106 FOREACH_END()
108 vlc_mutex_unlock( &p_mgr->p_sys->lock );
109 return false;
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 )
119 case CMD_ACTIVATE:
120 case CMD_DEACTIVATE:
121 case CMD_CLICK: // Arg1 must not be freed
122 break;
124 case CMD_TRIGGERMENU:
125 case CMD_PLAYING_CHANGED:
126 free( command->data[0] ); // Arg1 is int*, to free
127 break;
129 default:
130 break;
132 free( command );
133 FreeCommands( next );
136 /** Deactivate this extension: pushes immediate command and drops queued */
137 int Deactivate( extensions_manager_t *p_mgr, extension_t *p_ext )
139 (void) p_mgr;
140 vlc_mutex_lock( &p_ext->p_sys->command_lock );
142 if( p_ext->p_sys->b_exiting )
144 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
145 return VLC_EGENERIC;
148 /* Free the list of commands */
149 if( p_ext->p_sys->command )
150 FreeCommands( p_ext->p_sys->command->next );
152 /* Push command */
153 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
154 cmd->i_command = CMD_DEACTIVATE;
155 if( p_ext->p_sys->command )
156 p_ext->p_sys->command->next = cmd;
157 else
158 p_ext->p_sys->command = cmd;
160 vlc_cond_signal( &p_ext->p_sys->wait );
161 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
163 return VLC_SUCCESS;
166 /** Remove an extension from the activated list */
167 static int RemoveActivated( extensions_manager_t *p_mgr, extension_t *p_ext )
169 if( p_mgr->p_sys->b_killed )
170 return VLC_SUCCESS;
171 vlc_mutex_lock( &p_mgr->p_sys->lock );
173 int i_idx = -1;
174 extension_t *p_iter;
175 FOREACH_ARRAY( p_iter, p_mgr->p_sys->activated_extensions )
177 i_idx++;
178 if( !p_iter )
180 i_idx = -1;
181 break;
183 assert( p_iter->psz_name != NULL );
184 if( !strcmp( p_iter->psz_name, p_ext->psz_name ) )
185 break;
187 FOREACH_END()
189 if( i_idx >= 0 )
191 ARRAY_REMOVE( p_mgr->p_sys->activated_extensions, i_idx );
193 else
195 msg_Dbg( p_mgr, "Can't find extension '%s' in the activated list",
196 p_ext->psz_title );
199 vlc_mutex_unlock( &p_mgr->p_sys->lock );
200 return (i_idx >= 0) ? VLC_SUCCESS : VLC_EGENERIC;
203 /** Wait for an extension to finish */
204 void WaitForDeactivation( extension_t *p_ext )
206 vlc_join( p_ext->p_sys->thread, NULL );
209 /** Push a UI command */
210 int __PushCommand( extension_t *p_ext, bool b_unique, command_type_e i_command,
211 va_list args )
213 vlc_mutex_lock( &p_ext->p_sys->command_lock );
215 /* Create command */
216 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
217 cmd->i_command = i_command;
218 switch( i_command )
220 case CMD_CLICK:
221 cmd->data[0] = va_arg( args, void* );
222 break;
223 case CMD_TRIGGERMENU:
225 int *pi = malloc( sizeof( int ) );
226 if( !pi )
228 free( cmd );
229 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
230 return VLC_ENOMEM;
232 *pi = va_arg( args, int );
233 cmd->data[0] = pi;
235 break;
236 case CMD_PLAYING_CHANGED:
238 int *pi = malloc( sizeof( int ) );
239 if( !pi )
241 free( cmd );
242 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
243 return VLC_ENOMEM;
245 *pi = va_arg( args, int );
246 cmd->data[0] = pi;
248 break;
249 case CMD_CLOSE:
250 case CMD_SET_INPUT:
251 case CMD_UPDATE_META:
252 // Nothing to do here
253 break;
254 default:
255 msg_Dbg( p_ext->p_sys->p_mgr,
256 "Unknown command send to extension: %d", i_command );
257 break;
260 /* Push command to the end of the queue */
261 struct command_t *last = p_ext->p_sys->command;
262 if( !last )
264 p_ext->p_sys->command = cmd;
266 else
268 bool b_skip = false;
269 while( last->next != NULL )
271 if( b_unique && last->i_command == i_command )
273 // Do not push this 'unique' command a second time
274 b_skip = !memcmp( last->data, cmd->data, sizeof( cmd->data ) );
275 break;
277 else
279 last = last->next;
282 if( !b_skip )
284 last->next = cmd;
286 else
288 FreeCommands( cmd );
292 vlc_cond_signal( &p_ext->p_sys->wait );
293 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
294 return VLC_SUCCESS;
297 /* Thread loop */
298 static void* Run( void *data )
300 extension_t *p_ext = data;
301 extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
303 vlc_mutex_lock( &p_ext->p_sys->command_lock );
305 while( !p_ext->p_sys->b_exiting )
307 /* Pop command in front */
308 struct command_t *cmd = p_ext->p_sys->command;
309 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
311 /* Run command */
312 if( cmd )
314 if( LockExtension( p_ext ) )
316 switch( cmd->i_command )
318 case CMD_ACTIVATE:
320 if( lua_ExecuteFunction( p_mgr, p_ext, "activate", LUA_END ) < 0 )
322 msg_Err( p_mgr, "Could not activate extension!" );
323 Deactivate( p_mgr, p_ext );
324 cmd = NULL;
326 break;
329 case CMD_DEACTIVATE:
331 msg_Dbg( p_mgr, "Deactivating '%s'", p_ext->psz_title );
332 if( lua_ExtensionDeactivate( p_mgr, p_ext ) < 0 )
334 msg_Warn( p_mgr, "Extension '%s' did not deactivate properly",
335 p_ext->psz_title );
337 p_ext->p_sys->b_exiting = true;
338 RemoveActivated( p_mgr, p_ext );
339 break;
342 case CMD_CLOSE:
344 lua_ExecuteFunction( p_mgr, p_ext, "close", LUA_END );
345 break;
348 case CMD_CLICK:
350 extension_widget_t *p_widget = cmd->data[0];
351 assert( p_widget );
352 msg_Dbg( p_mgr, "Clicking '%s': '%s'",
353 p_ext->psz_name, p_widget->psz_text );
354 if( !lua_ExtensionWidgetClick( p_mgr, p_ext, p_widget )
355 < 0 )
357 msg_Warn( p_mgr, "Could not translate click" );
359 break;
362 case CMD_TRIGGERMENU:
364 int *pi_id = cmd->data[0];
365 assert( pi_id );
366 msg_Dbg( p_mgr, "Trigger menu %d of '%s'",
367 *pi_id, p_ext->psz_name );
368 lua_ExtensionTriggerMenu( p_mgr, p_ext, *pi_id );
369 break;
372 case CMD_SET_INPUT:
374 lua_ExecuteFunction( p_mgr, p_ext, "input_changed", LUA_END );
375 break;
378 case CMD_UPDATE_META:
380 lua_ExecuteFunction( p_mgr, p_ext, "meta_changed", LUA_END );
381 break;
384 case CMD_PLAYING_CHANGED:
386 lua_ExecuteFunction( p_mgr, p_ext, "playing_changed",
387 LUA_NUM, *((int *)cmd->data[0]), LUA_END );
388 break;
391 default:
393 msg_Dbg( p_mgr, "Unknown command in extension command queue: %d",
394 cmd->i_command );
395 break;
398 UnlockExtension( p_ext );
402 vlc_mutex_lock( &p_ext->p_sys->command_lock );
403 if( p_ext->p_sys->command )
405 cmd = p_ext->p_sys->command;
406 p_ext->p_sys->command = cmd->next;
407 cmd->next = NULL; // This prevents FreeCommands from freeing next
408 FreeCommands( cmd );
411 if( !p_ext->p_sys->b_exiting && !p_ext->p_sys->command )
413 vlc_cond_wait( &p_ext->p_sys->wait, &p_ext->p_sys->command_lock );
417 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
418 msg_Dbg( p_mgr, "Extension thread end: '%s'", p_ext->psz_title );
420 // Note: At this point, the extension should be deactivated
421 return NULL;