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 case CMD_PLAYING_CHANGED
:
126 free( command
->data
[0] ); // Arg1 is int*, to free
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
)
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
);
148 /* Free the list of commands */
149 if( p_ext
->p_sys
->command
)
150 FreeCommands( p_ext
->p_sys
->command
->next
);
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
;
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
);
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
)
171 vlc_mutex_lock( &p_mgr
->p_sys
->lock
);
175 FOREACH_ARRAY( p_iter
, p_mgr
->p_sys
->activated_extensions
)
183 assert( p_iter
->psz_name
!= NULL
);
184 if( !strcmp( p_iter
->psz_name
, p_ext
->psz_name
) )
191 ARRAY_REMOVE( p_mgr
->p_sys
->activated_extensions
, i_idx
);
195 msg_Dbg( p_mgr
, "Can't find extension '%s' in the activated list",
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
,
213 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
216 struct command_t
*cmd
= calloc( 1, sizeof( struct command_t
) );
217 cmd
->i_command
= i_command
;
221 cmd
->data
[0] = va_arg( args
, void* );
223 case CMD_TRIGGERMENU
:
225 int *pi
= malloc( sizeof( int ) );
229 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
232 *pi
= va_arg( args
, int );
236 case CMD_PLAYING_CHANGED
:
238 int *pi
= malloc( sizeof( int ) );
242 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
245 *pi
= va_arg( args
, int );
251 case CMD_UPDATE_META
:
252 // Nothing to do here
255 msg_Dbg( p_ext
->p_sys
->p_mgr
,
256 "Unknown command send to extension: %d", i_command
);
260 /* Push command to the end of the queue */
261 struct command_t
*last
= p_ext
->p_sys
->command
;
264 p_ext
->p_sys
->command
= cmd
;
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
) );
292 vlc_cond_signal( &p_ext
->p_sys
->wait
);
293 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
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
);
314 if( LockExtension( p_ext
) )
316 switch( cmd
->i_command
)
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
);
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",
337 p_ext
->p_sys
->b_exiting
= true;
338 RemoveActivated( p_mgr
, p_ext
);
344 lua_ExecuteFunction( p_mgr
, p_ext
, "close", LUA_END
);
350 extension_widget_t
*p_widget
= cmd
->data
[0];
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
)
357 msg_Warn( p_mgr
, "Could not translate click" );
362 case CMD_TRIGGERMENU
:
364 int *pi_id
= cmd
->data
[0];
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
);
374 lua_ExecuteFunction( p_mgr
, p_ext
, "input_changed", LUA_END
);
378 case CMD_UPDATE_META
:
380 lua_ExecuteFunction( p_mgr
, p_ext
, "meta_changed", LUA_END
);
384 case CMD_PLAYING_CHANGED
:
386 lua_ExecuteFunction( p_mgr
, p_ext
, "playing_changed",
387 LUA_NUM
, *((int *)cmd
->data
[0]), LUA_END
);
393 msg_Dbg( p_mgr
, "Unknown command in extension command queue: %d",
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
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