1 /*****************************************************************************
2 * interaction.c: User interaction functions
3 *****************************************************************************
4 * Copyright (C) 1998-2004 VideoLAN
5 * $Id: interface.c 10147 2005-03-05 17:18:30Z gbazin $
7 * Authors: Clément Stenac <zorglub@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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
26 * This file contains functions related to user interaction management
29 /*****************************************************************************
31 *****************************************************************************/
32 #include <stdlib.h> /* free(), strtol() */
33 #include <stdio.h> /* FILE */
34 #include <string.h> /* strerror() */
37 #include <vlc/input.h>
39 #include "vlc_interaction.h"
40 #include "vlc_interface.h"
41 #include "vlc_playlist.h"
43 /*****************************************************************************
45 *****************************************************************************/
46 static void intf_InteractionInit( playlist_t *p_playlist );
47 static interaction_t * intf_InteractionGet( vlc_object_t *p_this );
48 static void intf_InteractionSearchInterface( interaction_t *
50 static int intf_WaitAnswer( interaction_t *p_interact,
51 interaction_dialog_t *p_dialog );
52 static int intf_Send( interaction_t *p_interact,
53 interaction_dialog_t *p_dialog );
54 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* , int );
57 * Send an interaction element to the user
59 * \param p_this the calling vlc_object_t
60 * \param p_interact the interaction element
61 * \return VLC_SUCCESS or an error code
63 int __intf_Interact( vlc_object_t *p_this, interaction_dialog_t *
67 interaction_t *p_interaction = intf_InteractionGet( p_this );
69 /* Get an id, if we don't already have one */
70 if( p_dialog->i_id == 0 )
72 p_dialog->i_id = ++p_interaction->i_last_id;
75 if( p_dialog->i_type == INTERACT_ASK )
77 return intf_WaitAnswer( p_interaction, p_dialog );
81 return intf_Send( p_interaction, p_dialog );
86 * Destroy the interaction system
88 void intf_InteractionDestroy( interaction_t *p_interaction )
90 /// \todo Code this, and call it
94 * The main interaction processing loop
95 * This function is called from the playlist loop
97 * \param p_playlist the parent playlist
100 void intf_InteractionManage( playlist_t *p_playlist )
103 interaction_t *p_interaction;
105 p_interaction = p_playlist->p_interaction;
108 if( p_interaction->i_dialogs == 0 ) return;
110 vlc_mutex_lock( &p_interaction->object_lock );
112 intf_InteractionSearchInterface( p_interaction );
114 if( !p_interaction->p_intf )
116 vlc_mutex_unlock( &p_interaction->object_lock );
118 /// \todo Remove all dialogs as we can't display them
122 vlc_object_yield( p_interaction->p_intf );
124 for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
126 interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index];
128 switch( p_dialog->i_status )
130 case ANSWERED_DIALOG:
131 /// \todo Signal we have an answer
132 // - If have answer, signal what is waiting
133 // (vlc_cond ? dangerous in case of pb ?)
135 // Ask interface to hide it
136 msg_Dbg( p_interaction, "Hiding dialog %i", p_dialog->i_id );
137 p_interaction->p_intf->pf_interact( p_interaction->p_intf,
138 p_dialog, INTERACT_HIDE );
139 p_dialog->i_status = HIDING_DIALOG;
142 p_interaction->p_intf->pf_interact( p_interaction->p_intf,
143 p_dialog, INTERACT_UPDATE );
144 p_dialog->i_status = SENT_DIALOG;
145 msg_Dbg( p_interaction, "Updating dialog %i, %i widgets",
146 p_dialog->i_id, p_dialog->i_widgets );
149 if( !p_dialog->b_reusable )
151 /// \todo Destroy the dialog
155 // This is truly a new dialog, send it.
156 p_interaction->p_intf->pf_interact( p_interaction->p_intf,
157 p_dialog, INTERACT_NEW );
158 msg_Dbg( p_interaction, "Creating dialog %i, %i widgets",
159 p_dialog->i_id, p_dialog->i_widgets );
160 p_dialog->i_status = SENT_DIALOG;
165 vlc_object_release( p_interaction->p_intf );
167 vlc_mutex_unlock( &p_playlist->p_interaction->object_lock );
172 #define INTERACT_INIT( new ) \
173 new = (interaction_dialog_t*)malloc( \
174 sizeof( interaction_dialog_t ) ); \
175 new->i_widgets = 0; \
176 new->pp_widgets = NULL; \
177 new->psz_title = NULL; \
178 new->psz_description = NULL; \
180 new->i_status = NEW_DIALOG;
182 #define INTERACT_FREE( new ) \
183 if( new->psz_title ) free( new->psz_title ); \
184 if( new->psz_description ) free( new->psz_description );
186 /** Helper function to send a fatal message
187 * \param p_this Parent vlc_object
188 * \param i_id A predefined ID, 0 if not applicable
189 * \param psz_title Title for the dialog
190 * \param psz_format The message to display
192 void __intf_UserFatal( vlc_object_t *p_this, int i_id,
193 const char *psz_title,
194 const char *psz_format, ... )
197 interaction_dialog_t *p_new = NULL;
198 user_widget_t *p_widget = NULL;
202 p_new = intf_InteractionGetById( p_this, i_id );
206 INTERACT_INIT( p_new );
207 if( i_id > 0 ) p_new->i_id = i_id ;
211 p_new->i_status = UPDATED_DIALOG;
214 p_new->i_type = INTERACT_FATAL;
215 p_new->psz_title = strdup( psz_title );
217 p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) );
219 p_widget->i_type = WIDGET_TEXT;
221 va_start( args, psz_format );
222 vasprintf( &p_widget->psz_text, psz_format, args );
225 INSERT_ELEM ( p_new->pp_widgets,
230 intf_Interact( p_this, p_new );
234 /** Helper function to build a progress bar
235 * \param p_this Parent vlc object
237 interaction_dialog_t *__intf_ProgressBuild( vlc_object_t *p_this,
238 const char *psz_text )
240 interaction_dialog_t *p_new = (interaction_dialog_t *)malloc(
241 sizeof( interaction_dialog_t ) );
250 /**********************************************************************
251 * The following functions are local
252 **********************************************************************/
254 /* Get the interaction object. Create it if needed */
255 static interaction_t * intf_InteractionGet( vlc_object_t *p_this )
257 playlist_t *p_playlist;
258 interaction_t *p_interaction;
260 p_playlist = (playlist_t*) vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
268 if( p_playlist->p_interaction == NULL )
270 intf_InteractionInit( p_playlist );
273 p_interaction = p_playlist->p_interaction;
275 vlc_object_release( p_playlist );
277 return p_interaction;
280 /* Create the interaction object in the given playlist object */
281 static void intf_InteractionInit( playlist_t *p_playlist )
283 interaction_t *p_interaction;
285 msg_Dbg( p_playlist, "initializing interaction system" );
287 p_interaction = vlc_object_create( VLC_OBJECT( p_playlist ),
288 sizeof( interaction_t ) );
291 msg_Err( p_playlist,"out of memory" );
295 p_interaction->i_dialogs = 0;
296 p_interaction->pp_dialogs = NULL;
297 p_interaction->p_intf = NULL;
298 p_interaction->i_last_id = DIALOG_LAST_PREDEFINED + 1;
300 vlc_mutex_init( p_interaction , &p_interaction->object_lock );
302 p_playlist->p_interaction = p_interaction;
305 /* Look for an interface suitable for interaction */
306 static void intf_InteractionSearchInterface( interaction_t *p_interaction )
311 p_interaction->p_intf = NULL;
313 p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE );
316 msg_Err( p_interaction, "Unable to create module list" );
320 for( i_index = 0; i_index < p_list->i_count; i_index ++ )
322 intf_thread_t *p_intf = (intf_thread_t *)
323 p_list->p_values[i_index].p_object;
324 if( p_intf->pf_interact != NULL )
326 p_interaction->p_intf = p_intf;
330 vlc_list_release ( p_list );
333 /* Add a dialog to the queue and wait for answer */
334 static int intf_WaitAnswer( interaction_t *p_interact, interaction_dialog_t *p_dialog )
336 // TODO: Add to queue, wait for answer
340 /* Add a dialog to the queue and return */
341 static int intf_Send( interaction_t *p_interact, interaction_dialog_t *p_dialog )
343 vlc_mutex_lock( &p_interact->object_lock );
345 /// \todo Check first it does not exist !!!
346 INSERT_ELEM( p_interact->pp_dialogs,
347 p_interact->i_dialogs,
348 p_interact->i_dialogs,
350 vlc_mutex_unlock( &p_interact->object_lock );
354 /* Find an interaction dialog by its id */
355 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* p_this,
358 interaction_t *p_interaction = intf_InteractionGet( p_this );
361 for( i = 0 ; i< p_interaction->i_dialogs; i++ )
363 if( p_interaction->pp_dialogs[i]->i_id == i_id )
365 return p_interaction->pp_dialogs[i];