qt: playlist: use item title if available
[vlc.git] / 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 VLC authors and VideoLAN
7  *
8  * Authors: Vincent Seguin <seguin@via.ecp.fr>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /**
26  *   \file
27  *   This file contains functions related to interface management
28  */
29
30
31 /*****************************************************************************
32  * Preamble
33  *****************************************************************************/
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <unistd.h>
40
41 #include <vlc_common.h>
42 #include <vlc_modules.h>
43 #include <vlc_interface.h>
44 #include <vlc_playlist.h>
45 #include "libvlc.h"
46 #include "../lib/libvlc_internal.h"
47 #include "player/player.h"
48
49 static int AddIntfCallback( vlc_object_t *, char const *,
50                             vlc_value_t , vlc_value_t , void * );
51
52 static void
53 PlaylistConfigureFromVariables(vlc_playlist_t *playlist, vlc_object_t *obj)
54 {
55     enum vlc_playlist_playback_order order;
56     if (var_InheritBool(obj, "random"))
57         order = VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
58     else
59         order = VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL;
60
61     /* repeat = repeat current; loop = repeat all */
62     enum vlc_playlist_playback_repeat repeat;
63     if (var_InheritBool(obj, "repeat"))
64         repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT;
65     else if (var_InheritBool(obj, "loop"))
66         repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
67     else
68         repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
69
70     enum vlc_player_media_stopped_action media_stopped_action;
71     if (var_InheritBool(obj, "play-and-exit"))
72         media_stopped_action = VLC_PLAYER_MEDIA_STOPPED_EXIT;
73     else if (var_InheritBool(obj, "play-and-stop"))
74         media_stopped_action = VLC_PLAYER_MEDIA_STOPPED_STOP;
75     else if (var_InheritBool(obj, "play-and-pause"))
76         media_stopped_action = VLC_PLAYER_MEDIA_STOPPED_PAUSE;
77     else
78         media_stopped_action = VLC_PLAYER_MEDIA_STOPPED_CONTINUE;
79
80     bool start_paused = var_InheritBool(obj, "start-paused");
81     bool playlist_cork = var_InheritBool(obj, "playlist-cork");
82
83     vlc_playlist_Lock(playlist);
84     vlc_playlist_SetPlaybackOrder(playlist, order);
85     vlc_playlist_SetPlaybackRepeat(playlist, repeat);
86
87     vlc_player_t *player = vlc_playlist_GetPlayer(playlist);
88
89     /* the playlist and the player share the same lock, and this is not an
90      * implementation detail */
91     vlc_player_SetMediaStoppedAction(player, media_stopped_action);
92     vlc_player_SetStartPaused(player, start_paused);
93     vlc_player_SetPauseOnCork(player, playlist_cork);
94
95     vlc_playlist_Unlock(playlist);
96 }
97
98 static vlc_playlist_t *
99 libvlc_GetMainPlaylist(libvlc_int_t *libvlc)
100 {
101     libvlc_priv_t *priv = libvlc_priv(libvlc);
102
103     vlc_mutex_lock(&priv->lock);
104     vlc_playlist_t *playlist = priv->main_playlist;
105     if (priv->main_playlist == NULL)
106     {
107         playlist = priv->main_playlist = vlc_playlist_New(VLC_OBJECT(libvlc));
108         if (playlist)
109             PlaylistConfigureFromVariables(playlist, VLC_OBJECT(libvlc));
110     }
111     vlc_mutex_unlock(&priv->lock);
112
113     return playlist;
114 }
115
116 vlc_playlist_t *
117 vlc_intf_GetMainPlaylist(intf_thread_t *intf)
118 {
119     vlc_playlist_t *pl = libvlc_GetMainPlaylist(vlc_object_instance(intf));
120     assert(pl);
121     return pl;
122 }
123
124 /**
125  * Create and start an interface.
126  *
127  * @param playlist playlist and parent object for the interface
128  * @param chain configuration chain string
129  * @return VLC_SUCCESS or an error code
130  */
131 int intf_Create( libvlc_int_t *libvlc, const char *chain )
132 {
133     assert( libvlc );
134     libvlc_priv_t *priv = libvlc_priv(libvlc);
135
136     /* Ensure that each interfaces can access the main playlist */
137     if (libvlc_GetMainPlaylist(libvlc) == NULL)
138         return VLC_ENOMEM;
139
140     /* Allocate structure */
141     intf_thread_t *p_intf = vlc_custom_create( libvlc, sizeof( *p_intf ),
142                                                "interface" );
143     if( unlikely(p_intf == NULL) )
144         return VLC_ENOMEM;
145
146     /* Variable used for interface spawning */
147     vlc_value_t val;
148     var_Create( p_intf, "intf-add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
149     var_Change( p_intf, "intf-add", VLC_VAR_SETTEXT, _("Add Interface") );
150 #if !defined(_WIN32) && defined(HAVE_ISATTY)
151     if( isatty( 0 ) )
152 #endif
153     {
154         val.psz_string = (char *)"rc,none";
155         var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, val, _("Console") );
156     }
157     val.psz_string = (char *)"telnet,none";
158     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, val, _("Telnet") );
159     val.psz_string = (char *)"http,none";
160     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, val, _("Web") );
161     val.psz_string = (char *)"gestures,none";
162     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, val,
163                 _("Mouse Gestures") );
164
165     var_AddCallback( p_intf, "intf-add", AddIntfCallback, NULL );
166
167     /* Choose the best module */
168     char *module;
169
170     p_intf->p_cfg = NULL;
171     free( config_ChainCreate( &module, &p_intf->p_cfg, chain ) );
172     p_intf->p_module = module_need( p_intf, "interface", module, true );
173     free(module);
174     if( p_intf->p_module == NULL )
175     {
176         msg_Err( p_intf, "no suitable interface module" );
177         goto error;
178     }
179
180     vlc_mutex_lock(&priv->lock);
181     p_intf->p_next = priv->interfaces;
182     priv->interfaces = p_intf;
183     vlc_mutex_unlock(&priv->lock);
184
185     return VLC_SUCCESS;
186
187 error:
188     if( p_intf->p_module )
189         module_unneed( p_intf, p_intf->p_module );
190     config_ChainDestroy( p_intf->p_cfg );
191     vlc_object_delete(p_intf);
192     return VLC_EGENERIC;
193 }
194
195 /**
196  * Inserts an item in the playlist.
197  *
198  * This function is used during initialization. It inserts an item to the
199  * beginning of the playlist. That is meant to compensate for the reverse
200  * parsing order of the command line.
201  */
202 int intf_InsertItem(libvlc_int_t *libvlc, const char *mrl, unsigned optc,
203                     const char *const *optv, unsigned flags)
204 {
205     input_item_t *item = input_item_New(mrl, NULL);
206
207     if (unlikely(item == NULL))
208         return -1;
209
210     int ret = -1;
211
212     if (input_item_AddOptions(item, optc, optv, flags) == VLC_SUCCESS)
213     {
214         vlc_playlist_t *playlist = libvlc_GetMainPlaylist(libvlc);
215         if (playlist)
216         {
217             vlc_playlist_Lock(playlist);
218             ret = vlc_playlist_InsertOne(playlist, 0, item);
219             vlc_playlist_Unlock(playlist);
220         }
221     }
222     input_item_Release(item);
223     return ret;
224 }
225
226 void libvlc_InternalPlay(libvlc_int_t *libvlc)
227 {
228     if (!var_InheritBool(VLC_OBJECT(libvlc), "playlist-autostart"))
229         return;
230     vlc_playlist_t *playlist = libvlc_GetMainPlaylist(libvlc);
231     if (!playlist)
232         return;
233     vlc_playlist_Lock(playlist);
234     if (vlc_playlist_Count(playlist) > 0)
235     {
236         if (vlc_playlist_GetCurrentIndex(playlist) < 0)
237             vlc_playlist_GoTo(playlist, 0);
238         vlc_playlist_Start(playlist);
239     }
240     vlc_playlist_Unlock(playlist);
241 }
242
243 static void libvlc_AutoRun(libvlc_int_t *libvlc)
244 {
245     struct vlc_logger *log = libvlc->obj.logger;
246     module_t **mods;
247     ssize_t total = vlc_module_match("autorun", NULL, false, &mods, NULL);
248
249     for (ssize_t i = 0; i < total; i++) {
250         void (*func)(libvlc_int_t *) = vlc_module_map(log, mods[i]);
251
252         assert(func != NULL);
253         func(libvlc);
254     }
255
256     free(mods);
257 }
258
259 /**
260  * Starts an interface plugin.
261  */
262 int libvlc_InternalAddIntf(libvlc_int_t *libvlc, const char *name)
263 {
264     int ret;
265
266     if (name != NULL)
267         ret = intf_Create(libvlc, name);
268     else
269     {   /* Default interface */
270         libvlc_AutoRun(libvlc);
271
272         char *intf = var_InheritString(libvlc, "intf");
273         if (intf == NULL) /* "intf" has not been set */
274             msg_Info(libvlc, _("Running vlc with the default interface. "
275                      "Use 'cvlc' to use vlc without interface."));
276
277         ret = intf_Create(libvlc, intf);
278         free(intf);
279         name = "default";
280     }
281     if (ret != VLC_SUCCESS)
282         msg_Err(libvlc, "interface \"%s\" initialization failed", name);
283     return ret;
284 }
285
286 /**
287  * Stops and destroys all interfaces, then the playlist.
288  * @warning FIXME
289  * @param libvlc the LibVLC instance
290  */
291 void intf_DestroyAll(libvlc_int_t *libvlc)
292 {
293     libvlc_priv_t *priv = libvlc_priv(libvlc);
294
295     vlc_mutex_lock(&priv->lock);
296     intf_thread_t *intf, **pp = &priv->interfaces;
297
298     while ((intf = *pp) != NULL)
299     {
300         *pp = intf->p_next;
301         vlc_mutex_unlock(&priv->lock);
302
303         module_unneed(intf, intf->p_module);
304         config_ChainDestroy(intf->p_cfg);
305         var_DelCallback(intf, "intf-add", AddIntfCallback, NULL);
306         vlc_object_delete(intf);
307
308         vlc_mutex_lock(&priv->lock);
309     }
310     vlc_mutex_unlock(&priv->lock);
311 }
312
313 /* Following functions are local */
314
315 static int AddIntfCallback( vlc_object_t *obj, char const *var,
316                             vlc_value_t old, vlc_value_t cur, void *data )
317 {
318     int ret = intf_Create( vlc_object_instance(obj), cur.psz_string );
319     if( ret )
320         msg_Err( obj, "interface \"%s\" initialization failed",
321                  cur.psz_string );
322
323     (void) var; (void) old; (void) data;
324     return ret;
325 }