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 )
104 interaction_t *p_interaction;
106 p_interaction = p_playlist->p_interaction;
109 if( p_interaction->i_dialogs == 0 ) return;
111 vlc_mutex_lock( &p_interaction->object_lock );
113 intf_InteractionSearchInterface( p_interaction );
115 if( !p_interaction->p_intf )
117 vlc_mutex_unlock( &p_interaction->object_lock );
119 /// \todo Remove all dialogs as we can't display them
123 vlc_object_yield( p_interaction->p_intf );
125 for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
127 interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index];
129 switch( p_dialog->i_status )
131 case ANSWERED_DIALOG:
132 /// \todo Signal we have an answer
133 // - If have answer, signal what is waiting
134 // (vlc_cond ? dangerous in case of pb ?)
136 // Ask interface to hide it
137 msg_Dbg( p_interaction, "Hiding dialog %i", p_dialog->i_id );
138 p_dialog->i_action = INTERACT_HIDE;
139 val.p_address = p_dialog;
140 var_Set( p_interaction->p_intf, "interaction", val );
141 p_dialog->i_status = HIDING_DIALOG;
144 p_dialog->i_action = INTERACT_UPDATE;
145 val.p_address = p_dialog;
146 var_Set( p_interaction->p_intf, "interaction", val );
147 p_dialog->i_status = SENT_DIALOG;
148 msg_Dbg( p_interaction, "Updating dialog %i, %i widgets",
149 p_dialog->i_id, p_dialog->i_widgets );
152 if( !p_dialog->b_reusable )
154 /// \todo Destroy the dialog
158 // This is truly a new dialog, send it.
159 p_dialog->i_action = INTERACT_NEW;
160 val.p_address = p_dialog;
161 var_Set( p_interaction->p_intf, "interaction", val );
162 msg_Dbg( p_interaction, "Creating dialog %i to interface %i, %i widgets",
163 p_dialog->i_id, p_interaction->p_intf->i_object_id, p_dialog->i_widgets );
164 p_dialog->i_status = SENT_DIALOG;
169 vlc_object_release( p_interaction->p_intf );
171 vlc_mutex_unlock( &p_playlist->p_interaction->object_lock );
176 #define INTERACT_INIT( new ) \
177 new = (interaction_dialog_t*)malloc( \
178 sizeof( interaction_dialog_t ) ); \
179 new->i_widgets = 0; \
180 new->pp_widgets = NULL; \
181 new->psz_title = NULL; \
182 new->psz_description = NULL; \
184 new->i_status = NEW_DIALOG;
186 #define INTERACT_FREE( new ) \
187 if( new->psz_title ) free( new->psz_title ); \
188 if( new->psz_description ) free( new->psz_description );
190 /** Helper function to send a fatal message
191 * \param p_this Parent vlc_object
192 * \param i_id A predefined ID, 0 if not applicable
193 * \param psz_title Title for the dialog
194 * \param psz_format The message to display
196 void __intf_UserFatal( vlc_object_t *p_this, int i_id,
197 const char *psz_title,
198 const char *psz_format, ... )
201 interaction_dialog_t *p_new = NULL;
202 user_widget_t *p_widget = NULL;
206 p_new = intf_InteractionGetById( p_this, i_id );
210 INTERACT_INIT( p_new );
211 if( i_id > 0 ) p_new->i_id = i_id ;
215 p_new->i_status = UPDATED_DIALOG;
218 p_new->i_type = INTERACT_FATAL;
219 p_new->psz_title = strdup( psz_title );
221 p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) );
223 p_widget->i_type = WIDGET_TEXT;
225 va_start( args, psz_format );
226 vasprintf( &p_widget->psz_text, psz_format, args );
229 INSERT_ELEM ( p_new->pp_widgets,
234 intf_Interact( p_this, p_new );
238 /** Helper function to build a progress bar
239 * \param p_this Parent vlc object
241 interaction_dialog_t *__intf_ProgressBuild( vlc_object_t *p_this,
242 const char *psz_text )
244 interaction_dialog_t *p_new = (interaction_dialog_t *)malloc(
245 sizeof( interaction_dialog_t ) );
254 /**********************************************************************
255 * The following functions are local
256 **********************************************************************/
258 /* Get the interaction object. Create it if needed */
259 static interaction_t * intf_InteractionGet( vlc_object_t *p_this )
261 playlist_t *p_playlist;
262 interaction_t *p_interaction;
264 p_playlist = (playlist_t*) vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
272 if( p_playlist->p_interaction == NULL )
274 intf_InteractionInit( p_playlist );
277 p_interaction = p_playlist->p_interaction;
279 vlc_object_release( p_playlist );
281 return p_interaction;
284 /* Create the interaction object in the given playlist object */
285 static void intf_InteractionInit( playlist_t *p_playlist )
287 interaction_t *p_interaction;
289 msg_Dbg( p_playlist, "initializing interaction system" );
291 p_interaction = vlc_object_create( VLC_OBJECT( p_playlist ),
292 sizeof( interaction_t ) );
295 msg_Err( p_playlist,"out of memory" );
299 p_interaction->i_dialogs = 0;
300 p_interaction->pp_dialogs = NULL;
301 p_interaction->p_intf = NULL;
302 p_interaction->i_last_id = DIALOG_LAST_PREDEFINED + 1;
304 vlc_mutex_init( p_interaction , &p_interaction->object_lock );
306 p_playlist->p_interaction = p_interaction;
309 /* Look for an interface suitable for interaction */
310 static void intf_InteractionSearchInterface( interaction_t *p_interaction )
315 p_interaction->p_intf = NULL;
317 p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE );
320 msg_Err( p_interaction, "Unable to create module list" );
324 for( i_index = 0; i_index < p_list->i_count; i_index ++ )
326 intf_thread_t *p_intf = (intf_thread_t *)
327 p_list->p_values[i_index].p_object;
328 if( p_intf->b_interaction )
330 p_interaction->p_intf = p_intf;
334 vlc_list_release ( p_list );
337 /* Add a dialog to the queue and wait for answer */
338 static int intf_WaitAnswer( interaction_t *p_interact, interaction_dialog_t *p_dialog )
340 // TODO: Add to queue, wait for answer
344 /* Add a dialog to the queue and return */
345 static int intf_Send( interaction_t *p_interact, interaction_dialog_t *p_dialog )
347 vlc_mutex_lock( &p_interact->object_lock );
349 /// \todo Check first it does not exist !!!
350 INSERT_ELEM( p_interact->pp_dialogs,
351 p_interact->i_dialogs,
352 p_interact->i_dialogs,
354 vlc_mutex_unlock( &p_interact->object_lock );
358 /* Find an interaction dialog by its id */
359 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* p_this,
362 interaction_t *p_interaction = intf_InteractionGet( p_this );
365 for( i = 0 ; i< p_interaction->i_dialogs; i++ )
367 if( p_interaction->pp_dialogs[i]->i_id == i_id )
369 return p_interaction->pp_dialogs[i];