]> git.sesse.net Git - vlc/blob - src/interface/interface.c
Unexport var_OptionParse
[vlc] / src / interface / interface.c
1 /*****************************************************************************
2  * interface.c: interface access for other threads
3  * This library provides basic functions for threads to interact with user
4  * interface, such as command line.
5  *****************************************************************************
6  * Copyright (C) 1998-2007 the VideoLAN team
7  * $Id$
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /**
27  *   \file
28  *   This file contains functions related to interface management
29  */
30
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <vlc/vlc.h>
41
42 #include <vlc_aout.h>
43 #include <vlc_vout.h>
44
45 #include "vlc_interface.h"
46 #include "modules/modules.h" // Gruik!
47 #include "libvlc.h"
48
49 /*****************************************************************************
50  * Local prototypes
51  *****************************************************************************/
52 static void RunInterface( intf_thread_t *p_intf );
53
54 static int SwitchIntfCallback( vlc_object_t *, char const *,
55                                vlc_value_t , vlc_value_t , void * );
56 static int AddIntfCallback( vlc_object_t *, char const *,
57                             vlc_value_t , vlc_value_t , void * );
58
59 /*****************************************************************************
60  * intf_Create: prepare interface before main loop
61  *****************************************************************************
62  * This function opens output devices and creates specific interfaces. It sends
63  * its own error messages.
64  *****************************************************************************/
65 /**
66  * Create the interface, and prepare it for main loop.
67  * You can give some additional options to be used for interface initialization
68  *
69  * \param p_this the calling vlc_object_t
70  * \param psz_module a preferred interface module
71  * \param i_options number additional options
72  * \param ppsz_options additional option strings
73  * \return a pointer to the created interface thread, NULL on error
74  */
75 intf_thread_t* __intf_Create( vlc_object_t *p_this, const char *psz_module,
76                               int i_options, const char *const *ppsz_options  )
77 {
78     intf_thread_t * p_intf;
79     int i;
80
81     /* Allocate structure */
82     p_intf = vlc_object_create( p_this, VLC_OBJECT_INTF );
83     if( !p_intf )
84     {
85         msg_Err( p_this, "out of memory" );
86         return NULL;
87     }
88     p_intf->pf_request_window = NULL;
89     p_intf->pf_release_window = NULL;
90     p_intf->pf_control_window = NULL;
91     p_intf->b_play = VLC_FALSE;
92     p_intf->b_interaction = VLC_FALSE;
93     p_intf->b_should_run_on_first_thread = VLC_FALSE;
94
95     for( i = 0 ; i< i_options; i++ )
96         var_OptionParse( p_this, ppsz_options[i] );
97
98     /* Choose the best module */
99     p_intf->psz_intf = strdup( psz_module );
100     p_intf->p_module = module_Need( p_intf, "interface", psz_module, VLC_FALSE );
101
102     if( p_intf->p_module == NULL )
103     {
104         msg_Err( p_intf, "no suitable interface module" );
105         free( p_intf->psz_intf );
106         vlc_object_destroy( p_intf );
107         return NULL;
108     }
109
110     /* Initialize structure */
111     p_intf->b_menu        = VLC_FALSE;
112     p_intf->b_menu_change = VLC_FALSE;
113
114     /* Initialize mutexes */
115     vlc_mutex_init( p_intf, &p_intf->change_lock );
116
117     /* Attach interface to its parent object */
118     vlc_object_attach( p_intf, p_this );
119
120     return p_intf;
121 }
122
123 /*****************************************************************************
124  * intf_RunThread: launch the interface thread
125  *****************************************************************************
126  * This function either creates a new thread and runs the interface in it.
127  *****************************************************************************/
128 /**
129  * Starts and runs the interface thread.
130  *
131  * \param p_intf the interface thread
132  * \return VLC_SUCCESS on success, an error number else
133  */
134 int intf_RunThread( intf_thread_t *p_intf )
135 {
136     /* This interface doesn't need to be run */
137     if( p_intf->pf_run == NULL )
138         return VLC_SUCCESS;
139
140     /* Hack to get Mac OS X Cocoa runtime running
141      * (it needs access to the main thread) */
142     if( p_intf->b_should_run_on_first_thread )
143     {
144         RunInterface( p_intf );
145         return VLC_SUCCESS;
146     }
147     
148     /* Run the interface in a separate thread */
149     if( vlc_thread_create( p_intf, "interface", RunInterface,
150                            VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
151     {
152         msg_Err( p_intf, "cannot spawn interface thread" );
153         return VLC_EGENERIC;
154     }
155
156     return VLC_SUCCESS;
157 }
158
159 /**
160  * Stops the interface thread
161  *
162  * This function asks the interface thread to stop
163  * \param p_intf the interface thread
164  * \return nothing
165  */
166 void intf_StopThread( intf_thread_t *p_intf )
167 {
168     /* Tell the interface to die */
169     vlc_object_kill( p_intf );
170     if( p_intf->pf_run != NULL )
171     {
172         vlc_cond_signal( &p_intf->object_wait );
173         vlc_thread_join( p_intf );
174     }
175 }
176
177 /**
178  * \brief Destroy the interface after the main loop endeed.
179  *
180  * Destroys interfaces and closes output devices
181  * \param p_intf the interface thread
182  * \return nothing
183  */
184 void intf_Destroy( intf_thread_t *p_intf )
185 {
186     /* Unlock module if present (a switch may have failed) */
187     if( p_intf->p_module )
188     {
189         module_Unneed( p_intf, p_intf->p_module );
190     }
191     free( p_intf->psz_intf );
192
193     vlc_mutex_destroy( &p_intf->change_lock );
194
195     /* Free structure */
196     vlc_object_destroy( p_intf );
197 }
198
199
200 /* Following functions are local */
201
202 /*****************************************************************************
203  * RunInterface: setups necessary data and give control to the interface
204  *****************************************************************************/
205 static void RunInterface( intf_thread_t *p_intf )
206 {
207     static const char *ppsz_interfaces[] =
208     {
209         "skins2", "Skins 2",
210 #ifndef WIN32
211         "wxwidgets", "wxWidgets",
212 #endif
213         NULL, NULL
214     };
215     const char **ppsz_parser;
216
217     vlc_list_t *p_list;
218     int i;
219     vlc_value_t val, text;
220     char *psz_intf;
221
222     /* Variable used for interface switching */
223     p_intf->psz_switch_intf = NULL;
224     var_Create( p_intf, "intf-switch", VLC_VAR_STRING |
225                 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
226     text.psz_string = _("Switch interface");
227     var_Change( p_intf, "intf-switch", VLC_VAR_SETTEXT, &text, NULL );
228
229     /* Only fill the list with available modules */
230     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
231     for( ppsz_parser = ppsz_interfaces; *ppsz_parser; ppsz_parser += 2 )
232     {
233         for( i = 0; i < p_list->i_count; i++ )
234         {
235             module_t *p_module = (module_t *)p_list->p_values[i].p_object;
236             if( !strcmp( p_module->psz_object_name, ppsz_parser[0] ) )
237             {
238                 val.psz_string = (char *)ppsz_parser[0];
239                 text.psz_string = (char *)_(ppsz_parser[1]);
240                 var_Change( p_intf, "intf-switch", VLC_VAR_ADDCHOICE,
241                             &val, &text );
242                 break;
243             }
244         }
245     }
246     vlc_list_release( p_list );
247
248     var_AddCallback( p_intf, "intf-switch", SwitchIntfCallback, NULL );
249
250     /* Variable used for interface spawning */
251     var_Create( p_intf, "intf-add", VLC_VAR_STRING |
252                 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
253     text.psz_string = _("Add Interface");
254     var_Change( p_intf, "intf-add", VLC_VAR_SETTEXT, &text, NULL );
255
256     val.psz_string = (char *)"rc"; text.psz_string = (char *)"Console";
257     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
258     val.psz_string = (char *)"telnet";
259     text.psz_string = (char *)_("Telnet Interface");
260     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
261     val.psz_string = (char *)"http";
262     text.psz_string = (char *)_("Web Interface");
263     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
264     val.psz_string = (char *)"logger";
265     text.psz_string = (char *)_("Debug logging");
266     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
267     val.psz_string = (char *)"gestures";
268     text.psz_string = (char *)_("Mouse Gestures");
269     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
270
271     var_AddCallback( p_intf, "intf-add", AddIntfCallback, NULL );
272
273     do
274     {
275         /* Give control to the interface */
276         p_intf->pf_run( p_intf );
277
278         /* Reset play on start status */
279         p_intf->b_play = VLC_FALSE;
280
281         if( !p_intf->psz_switch_intf )
282         {
283             break;
284         }
285
286         /* Make sure the old interface is completely uninitialized */
287         module_Unneed( p_intf, p_intf->p_module );
288
289         /* Provide ability to switch the main interface on the fly */
290         psz_intf = p_intf->psz_switch_intf;
291         p_intf->psz_switch_intf = NULL;
292
293         vlc_mutex_lock( &p_intf->object_lock );
294         p_intf->b_die = VLC_FALSE; /* FIXME */
295         p_intf->b_dead = VLC_FALSE;
296
297         vlc_mutex_unlock( &p_intf->object_lock );
298
299         p_intf->psz_intf = psz_intf;
300         p_intf->p_module = module_Need( p_intf, "interface", psz_intf, 0 );
301     }
302     while( p_intf->p_module );
303 }
304
305 static int SwitchIntfCallback( vlc_object_t *p_this, char const *psz_cmd,
306                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
307 {
308     intf_thread_t *p_intf = (intf_thread_t *)p_this;
309     (void)psz_cmd; (void)oldval; (void)p_data;
310
311     p_intf->psz_switch_intf =
312         malloc( strlen(newval.psz_string) + sizeof(",none") );
313     sprintf( p_intf->psz_switch_intf, "%s,none", newval.psz_string );
314     vlc_object_kill( p_intf );
315
316     return VLC_SUCCESS;
317 }
318
319 static int AddIntfCallback( vlc_object_t *p_this, char const *psz_cmd,
320                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
321 {
322     intf_thread_t *p_intf;
323     char *psz_intf = malloc( strlen(newval.psz_string) + sizeof(",none") );
324
325     (void)psz_cmd; (void)oldval; (void)p_data;
326
327     /* Try to create the interface */
328     sprintf( psz_intf, "%s,none", newval.psz_string );
329     p_intf = intf_Create( p_this->p_libvlc, psz_intf, 0, NULL );
330     free( psz_intf );
331     if( p_intf == NULL )
332     {
333         msg_Err( p_this, "interface \"%s\" initialization failed",
334                  newval.psz_string );
335         return VLC_EGENERIC;
336     }
337
338     /* Try to run the interface */
339     if( intf_RunThread( p_intf ) != VLC_SUCCESS )
340     {
341         vlc_object_detach( p_intf );
342         intf_Destroy( p_intf );
343         return VLC_EGENERIC;
344     }
345
346     return VLC_SUCCESS;
347 }
348