1 /*****************************************************************************
2 * extension_thread.c: Extensions Manager, Threads manager (no Lua here)
3 *****************************************************************************
4 * Copyright (C) 2009-2010 VideoLAN and authors
6 * Authors: Jean-Philippe André < jpeg # videolan.org >
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
28 #include "extension.h"
33 extensions_manager_t
*p_mgr
;
38 static void* Run( void *data
);
39 static void FreeCommands( struct command_t
*command
);
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 vlc_mutex_lock( &p_sys
->command_lock
);
55 if ( p_sys
->b_activated
== false )
57 /* Prepare first command */
58 assert(p_sys
->command
== NULL
);
59 p_sys
->command
= calloc( 1, sizeof( struct command_t
) );
62 vlc_mutex_unlock( &p_sys
->command_lock
);
65 p_sys
->command
->i_command
= CMD_ACTIVATE
; /* No params */
66 if (p_sys
->b_thread_running
== true)
68 msg_Dbg( p_mgr
, "Reactivating extension %s", p_ext
->psz_title
);
69 vlc_cond_signal( &p_sys
->wait
);
72 vlc_mutex_unlock( &p_sys
->command_lock
);
74 if (p_sys
->b_thread_running
== true)
77 msg_Dbg( p_mgr
, "Activating extension '%s'", p_ext
->psz_title
);
79 p_sys
->b_exiting
= false;
80 p_sys
->b_thread_running
= true;
82 if( vlc_clone( &p_sys
->thread
, Run
, p_ext
, VLC_THREAD_PRIORITY_LOW
)
85 p_sys
->b_exiting
= true;
86 p_sys
->b_thread_running
= false;
93 /** Recursively drop and free commands starting from "command" */
94 static void FreeCommands( struct command_t
*command
)
96 if( !command
) return;
97 struct command_t
*next
= command
->next
;
98 switch( command
->i_command
)
102 case CMD_CLICK
: // Arg1 must not be freed
105 case CMD_TRIGGERMENU
:
106 case CMD_PLAYING_CHANGED
:
107 free( command
->data
[0] ); // Arg1 is int*, to free
114 FreeCommands( next
);
117 bool QueueDeactivateCommand( extension_t
*p_ext
)
119 struct command_t
*cmd
= calloc( 1, sizeof( struct command_t
) );
120 if( unlikely( cmd
== NULL
) )
122 /* Free the list of commands */
123 if( p_ext
->p_sys
->command
)
124 FreeCommands( p_ext
->p_sys
->command
->next
);
128 cmd
->i_command
= CMD_DEACTIVATE
;
129 if( p_ext
->p_sys
->command
)
130 p_ext
->p_sys
->command
->next
= cmd
;
132 p_ext
->p_sys
->command
= cmd
;
134 vlc_cond_signal( &p_ext
->p_sys
->wait
);
138 /** Deactivate this extension: pushes immediate command and drops queued */
139 int Deactivate( extensions_manager_t
*p_mgr
, extension_t
*p_ext
)
141 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
143 if( p_ext
->p_sys
->b_exiting
)
145 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
149 if( p_ext
->p_sys
->p_progress_id
!= NULL
)
151 // Extension is stuck, kill it now
152 vlc_dialog_release( p_mgr
, p_ext
->p_sys
->p_progress_id
);
153 p_ext
->p_sys
->p_progress_id
= NULL
;
154 KillExtension( p_mgr
, p_ext
);
155 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
159 bool b_success
= QueueDeactivateCommand( p_ext
);
160 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
162 return b_success
? VLC_SUCCESS
: VLC_ENOMEM
;
165 /* MUST be called with command_lock held */
166 void KillExtension( extensions_manager_t
*p_mgr
, extension_t
*p_ext
)
168 msg_Dbg( p_mgr
, "Killing extension now" );
169 vlclua_fd_interrupt( &p_ext
->p_sys
->dtable
);
170 p_ext
->p_sys
->b_activated
= false;
171 p_ext
->p_sys
->b_exiting
= true;
172 vlc_cond_signal( &p_ext
->p_sys
->wait
);
175 /** Push a UI command */
176 int PushCommand__( extension_t
*p_ext
, bool b_unique
, command_type_e i_command
,
180 struct command_t
*cmd
= calloc( 1, sizeof( struct command_t
) );
181 if( unlikely( cmd
== NULL
) )
183 cmd
->i_command
= i_command
;
187 cmd
->data
[0] = va_arg( args
, void* );
189 case CMD_TRIGGERMENU
:
191 int *pi
= malloc( sizeof( int ) );
197 *pi
= va_arg( args
, int );
201 case CMD_PLAYING_CHANGED
:
203 int *pi
= malloc( sizeof( int ) );
209 *pi
= va_arg( args
, int );
215 case CMD_UPDATE_META
:
216 // Nothing to do here
219 msg_Dbg( p_ext
->p_sys
->p_mgr
,
220 "Unknown command send to extension: %d", i_command
);
224 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
226 /* Push command to the end of the queue */
227 struct command_t
*last
= p_ext
->p_sys
->command
;
230 p_ext
->p_sys
->command
= cmd
;
235 while( last
->next
!= NULL
)
237 if( b_unique
&& last
->i_command
== i_command
)
239 // Do not push this 'unique' command a second time
240 b_skip
= !memcmp( last
->data
, cmd
->data
, sizeof( cmd
->data
) );
258 vlc_cond_signal( &p_ext
->p_sys
->wait
);
259 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
264 static void* Run( void *data
)
266 extension_t
*p_ext
= data
;
267 extensions_manager_t
*p_mgr
= p_ext
->p_sys
->p_mgr
;
269 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
271 while( !p_ext
->p_sys
->b_exiting
)
273 struct command_t
*cmd
= p_ext
->p_sys
->command
;
275 /* Pop command in front */
278 vlc_cond_wait( &p_ext
->p_sys
->wait
, &p_ext
->p_sys
->command_lock
);
281 p_ext
->p_sys
->command
= cmd
->next
;
282 cmd
->next
= NULL
; /* unlink command (for FreeCommands()) */
283 // Create watch timer
284 vlc_timer_schedule( p_ext
->p_sys
->timer
, false, WATCH_TIMER_PERIOD
,
285 VLC_TIMER_FIRE_ONCE
);
286 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
289 vlc_mutex_lock( &p_ext
->p_sys
->running_lock
);
290 switch( cmd
->i_command
)
294 if( lua_ExecuteFunction( p_mgr
, p_ext
, "activate", LUA_END
) < 0 )
296 msg_Err( p_mgr
, "Could not activate extension!" );
297 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
298 QueueDeactivateCommand( p_ext
);
299 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
302 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
303 p_ext
->p_sys
->b_activated
= true;
304 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
310 msg_Dbg( p_mgr
, "Deactivating '%s'", p_ext
->psz_title
);
311 if( lua_ExtensionDeactivate( p_mgr
, p_ext
) < 0 )
313 msg_Warn( p_mgr
, "Extension '%s' did not deactivate properly",
316 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
317 p_ext
->p_sys
->b_activated
= false;
318 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
324 lua_ExecuteFunction( p_mgr
, p_ext
, "close", LUA_END
);
330 extension_widget_t
*p_widget
= cmd
->data
[0];
332 msg_Dbg( p_mgr
, "Clicking '%s': '%s'",
333 p_ext
->psz_name
, p_widget
->psz_text
);
334 if( lua_ExtensionWidgetClick( p_mgr
, p_ext
, p_widget
) < 0 )
336 msg_Warn( p_mgr
, "Could not translate click" );
341 case CMD_TRIGGERMENU
:
343 int *pi_id
= cmd
->data
[0];
345 msg_Dbg( p_mgr
, "Trigger menu %d of '%s'",
346 *pi_id
, p_ext
->psz_name
);
347 lua_ExtensionTriggerMenu( p_mgr
, p_ext
, *pi_id
);
353 lua_ExecuteFunction( p_mgr
, p_ext
, "input_changed", LUA_END
);
357 case CMD_UPDATE_META
:
359 lua_ExecuteFunction( p_mgr
, p_ext
, "meta_changed", LUA_END
);
363 case CMD_PLAYING_CHANGED
:
365 lua_ExecuteFunction( p_mgr
, p_ext
, "playing_changed",
366 LUA_NUM
, *((int *)cmd
->data
[0]), LUA_END
);
372 msg_Dbg( p_mgr
, "Unknown command in extension command queue: %d",
377 vlc_mutex_unlock( &p_ext
->p_sys
->running_lock
);
381 vlc_mutex_lock( &p_ext
->p_sys
->command_lock
);
382 // Reset watch timer and timestamp
383 if( p_ext
->p_sys
->p_progress_id
!= NULL
)
385 vlc_dialog_release( p_mgr
, p_ext
->p_sys
->p_progress_id
);
386 p_ext
->p_sys
->p_progress_id
= NULL
;
388 vlc_timer_disarm( p_ext
->p_sys
->timer
);
391 vlc_mutex_unlock( &p_ext
->p_sys
->command_lock
);
392 msg_Dbg( p_mgr
, "Extension thread end: '%s'", p_ext
->psz_title
);
394 // Note: At this point, the extension should be deactivated