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 VLC authors and VideoLAN
8 * Authors: Vincent Seguin <seguin@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
27 * This file contains functions related to interface management
31 /*****************************************************************************
33 *****************************************************************************/
41 #include <vlc_common.h>
42 #include <vlc_modules.h>
43 #include <vlc_interface.h>
44 #include <vlc_playlist_legacy.h>
45 #include <vlc_playlist.h>
47 #include "playlist_legacy/playlist_internal.h"
48 #include "../lib/libvlc_internal.h"
49 #include "input/player.h"
51 static int AddIntfCallback( vlc_object_t
*, char const *,
52 vlc_value_t
, vlc_value_t
, void * );
54 /* This lock ensures that the playlist is created only once (per instance). It
55 * also protects the list of running interfaces against concurrent access,
56 * either to add or remove an interface.
58 * However, it does NOT protect from destruction of the playlist by
59 * intf_DestroyAll(). Instead, care must be taken that intf_Create() and any
60 * other function that depends on the playlist is only called BEFORE
61 * intf_DestroyAll() has the possibility to destroy all interfaces.
63 static vlc_mutex_t lock
= VLC_STATIC_MUTEX
;
66 * Creates the playlist if necessary, and return a pointer to it.
67 * @note The playlist is not reference-counted. So the pointer is only valid
68 * until intf_DestroyAll() destroys interfaces.
70 static playlist_t
*intf_GetPlaylist(libvlc_int_t
*libvlc
)
74 vlc_mutex_lock(&lock
);
75 playlist
= libvlc_priv(libvlc
)->playlist
;
78 playlist
= playlist_Create(VLC_OBJECT(libvlc
));
79 libvlc_priv(libvlc
)->playlist
= playlist
;
81 vlc_mutex_unlock(&lock
);
87 PlaylistConfigureFromVariables(vlc_playlist_t
*playlist
, vlc_object_t
*obj
)
89 enum vlc_playlist_playback_order order
;
90 if (var_InheritBool(obj
, "random"))
91 order
= VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
;
93 order
= VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL
;
95 /* repeat = repeat current; loop = repeat all */
96 enum vlc_playlist_playback_repeat repeat
;
97 if (var_InheritBool(obj
, "repeat"))
98 repeat
= VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT
;
99 else if (var_InheritBool(obj
, "loop"))
100 repeat
= VLC_PLAYLIST_PLAYBACK_REPEAT_ALL
;
102 repeat
= VLC_PLAYLIST_PLAYBACK_REPEAT_NONE
;
104 enum vlc_player_media_stopped_action media_stopped_action
;
105 if (var_InheritBool(obj
, "play-and-exit"))
106 media_stopped_action
= VLC_PLAYER_MEDIA_STOPPED_EXIT
;
107 else if (var_InheritBool(obj
, "play-and-stop"))
108 media_stopped_action
= VLC_PLAYER_MEDIA_STOPPED_STOP
;
109 else if (var_InheritBool(obj
, "play-and-pause"))
110 media_stopped_action
= VLC_PLAYER_MEDIA_STOPPED_PAUSE
;
112 media_stopped_action
= VLC_PLAYER_MEDIA_STOPPED_CONTINUE
;
114 bool start_paused
= var_InheritBool(obj
, "start-paused");
116 vlc_playlist_Lock(playlist
);
117 vlc_playlist_SetPlaybackOrder(playlist
, order
);
118 vlc_playlist_SetPlaybackRepeat(playlist
, repeat
);
120 vlc_player_t
*player
= vlc_playlist_GetPlayer(playlist
);
122 /* the playlist and the player share the same lock, and this is not an
123 * implementation detail */
124 vlc_player_SetMediaStoppedAction(player
, media_stopped_action
);
125 vlc_player_SetStartPaused(player
, start_paused
);
127 vlc_playlist_Unlock(playlist
);
131 vlc_intf_GetMainPlaylist(intf_thread_t
*intf
)
133 libvlc_int_t
*libvlc
= vlc_object_instance(intf
);
134 libvlc_priv_t
*priv
= libvlc_priv(libvlc
);
136 vlc_mutex_lock(&lock
);
137 vlc_playlist_t
*playlist
= priv
->main_playlist
;
138 if (priv
->main_playlist
== NULL
)
140 playlist
= priv
->main_playlist
= vlc_playlist_New(VLC_OBJECT(libvlc
));
142 PlaylistConfigureFromVariables(playlist
, VLC_OBJECT(libvlc
));
144 vlc_mutex_unlock(&lock
);
149 static int intf_CreateInternal( libvlc_int_t
*libvlc
, playlist_t
*playlist
,
152 assert( !!libvlc
!= !!playlist
);
155 playlist
= intf_GetPlaylist(libvlc
);
159 libvlc_priv_t
*priv
= libvlc_priv(vlc_object_instance(playlist
));
161 /* Allocate structure */
162 intf_thread_t
*p_intf
= vlc_custom_create( playlist
, sizeof( *p_intf
),
164 if( unlikely(p_intf
== NULL
) )
167 /* Variable used for interface spawning */
169 var_Create( p_intf
, "intf-add", VLC_VAR_STRING
| VLC_VAR_ISCOMMAND
);
170 var_Change( p_intf
, "intf-add", VLC_VAR_SETTEXT
, _("Add Interface") );
171 #if !defined(_WIN32) && defined(HAVE_ISATTY)
175 val
.psz_string
= (char *)"rc,none";
176 var_Change( p_intf
, "intf-add", VLC_VAR_ADDCHOICE
, val
, _("Console") );
178 val
.psz_string
= (char *)"telnet,none";
179 var_Change( p_intf
, "intf-add", VLC_VAR_ADDCHOICE
, val
, _("Telnet") );
180 val
.psz_string
= (char *)"http,none";
181 var_Change( p_intf
, "intf-add", VLC_VAR_ADDCHOICE
, val
, _("Web") );
182 val
.psz_string
= (char *)"gestures,none";
183 var_Change( p_intf
, "intf-add", VLC_VAR_ADDCHOICE
, val
,
184 _("Mouse Gestures") );
186 var_AddCallback( p_intf
, "intf-add", AddIntfCallback
, playlist
);
188 /* Choose the best module */
191 p_intf
->p_cfg
= NULL
;
192 free( config_ChainCreate( &module
, &p_intf
->p_cfg
, chain
) );
193 p_intf
->p_module
= module_need( p_intf
, "interface", module
, true );
195 if( p_intf
->p_module
== NULL
)
197 msg_Err( p_intf
, "no suitable interface module" );
201 vlc_mutex_lock( &lock
);
202 p_intf
->p_next
= priv
->interfaces
;
203 priv
->interfaces
= p_intf
;
204 vlc_mutex_unlock( &lock
);
209 if( p_intf
->p_module
)
210 module_unneed( p_intf
, p_intf
->p_module
);
211 config_ChainDestroy( p_intf
->p_cfg
);
212 vlc_object_delete(p_intf
);
217 * Create and start an interface.
219 * @param playlist playlist and parent object for the interface
220 * @param chain configuration chain string
221 * @return VLC_SUCCESS or an error code
223 int intf_Create( libvlc_int_t
*libvlc
, const char *chain
)
225 return intf_CreateInternal( libvlc
, NULL
, chain
);
229 * Inserts an item in the playlist.
231 * This function is used during initialization. Unlike playlist_Add() and
232 * variants, it inserts an item to the beginning of the playlist. That is
233 * meant to compensate for the reverse parsing order of the command line.
235 * @note This function may <b>not</b> be called at the same time as
238 int intf_InsertItem(libvlc_int_t
*libvlc
, const char *mrl
, unsigned optc
,
239 const char *const *optv
, unsigned flags
)
241 playlist_t
*playlist
= intf_GetPlaylist(libvlc
);
242 input_item_t
*item
= input_item_New(mrl
, NULL
);
244 if (unlikely(item
== NULL
))
249 if (input_item_AddOptions(item
, optc
, optv
, flags
) == VLC_SUCCESS
)
251 playlist_Lock(playlist
);
252 if (playlist_NodeAddInput(playlist
, item
, playlist
->p_playing
,
255 playlist_Unlock(playlist
);
257 input_item_Release(item
);
261 void libvlc_InternalPlay(libvlc_int_t
*libvlc
)
265 vlc_mutex_lock(&lock
);
266 pl
= libvlc_priv(libvlc
)->playlist
;
267 vlc_mutex_unlock(&lock
);
269 if (pl
!= NULL
&& var_GetBool(pl
, "playlist-autostart"))
270 playlist_Control(pl
, PLAYLIST_PLAY
, false);
274 * Starts an interface plugin.
276 int libvlc_InternalAddIntf(libvlc_int_t
*libvlc
, const char *name
)
278 playlist_t
*playlist
= intf_GetPlaylist(libvlc
);
281 if (unlikely(playlist
== NULL
))
285 ret
= intf_CreateInternal(NULL
, playlist
, name
);
287 { /* Default interface */
288 char *intf
= var_InheritString(libvlc
, "intf");
289 if (intf
== NULL
) /* "intf" has not been set */
291 #if !defined(_WIN32) && !defined(__OS2__)
292 if (!var_InheritBool(libvlc
, "daemon"))
294 msg_Info(libvlc
, _("Running vlc with the default interface. "
295 "Use 'cvlc' to use vlc without interface."));
297 ret
= intf_CreateInternal(NULL
, playlist
, intf
);
301 if (ret
!= VLC_SUCCESS
)
302 msg_Err(libvlc
, "interface \"%s\" initialization failed", name
);
307 * Stops and destroys all interfaces, then the playlist.
309 * @param libvlc the LibVLC instance
311 void intf_DestroyAll(libvlc_int_t
*libvlc
)
313 libvlc_priv_t
*priv
= libvlc_priv(libvlc
);
314 playlist_t
*playlist
;
316 vlc_mutex_lock(&lock
);
317 playlist
= libvlc_priv(libvlc
)->playlist
;
318 if (playlist
!= NULL
)
320 intf_thread_t
*intf
, **pp
= &priv
->interfaces
;
322 while ((intf
= *pp
) != NULL
)
325 vlc_mutex_unlock(&lock
);
327 module_unneed(intf
, intf
->p_module
);
328 config_ChainDestroy(intf
->p_cfg
);
329 var_DelCallback(intf
, "intf-add", AddIntfCallback
, playlist
);
330 vlc_object_delete(intf
);
332 vlc_mutex_lock(&lock
);
335 libvlc_priv(libvlc
)->playlist
= NULL
;
337 vlc_mutex_unlock(&lock
);
339 if (playlist
!= NULL
)
340 playlist_Destroy(playlist
);
343 /* Following functions are local */
345 static int AddIntfCallback( vlc_object_t
*obj
, char const *var
,
346 vlc_value_t old
, vlc_value_t cur
, void *data
)
348 playlist_t
*playlist
= data
;
350 int ret
= intf_CreateInternal( NULL
, playlist
, cur
.psz_string
);
352 msg_Err( obj
, "interface \"%s\" initialization failed",
355 (void) var
; (void) old
;