]> git.sesse.net Git - vlc/blob - src/interface/interaction.c
Interaction facility (Refs:#27)
[vlc] / src / interface / interaction.c
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 $
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /**
25  *   \file
26  *   This file contains functions related to user interaction management
27  */
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include <stdlib.h>                                      /* free(), strtol() */
33 #include <stdio.h>                                                   /* FILE */
34 #include <string.h>                                            /* strerror() */
35
36 #include <vlc/vlc.h>
37 #include <vlc/input.h>
38
39 #include "vlc_interaction.h"
40 #include "vlc_interface.h"
41 #include "vlc_playlist.h"
42
43 /*****************************************************************************
44  * Local prototypes
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 *
49                                                               p_interaction );
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 );
55
56 /**
57  * Send an interaction element to the user
58  *
59  * \param p_this the calling vlc_object_t
60  * \param p_interact the interaction element
61  * \return VLC_SUCCESS or an error code
62  */
63 int  __intf_Interact( vlc_object_t *p_this, interaction_dialog_t *
64                                     p_dialog )
65 {
66
67     interaction_t *p_interaction = intf_InteractionGet( p_this );
68
69     /* Get an id, if we don't already have one */
70     if( p_dialog->i_id == 0 )
71     {
72         p_dialog->i_id = ++p_interaction->i_last_id;
73     }
74
75     if( p_dialog->i_type == INTERACT_ASK )
76     {
77         return intf_WaitAnswer( p_interaction, p_dialog );
78     }
79     else
80     {
81         return intf_Send( p_interaction, p_dialog );
82     }
83 }
84
85 /** 
86  * Destroy the interaction system
87  */
88 void intf_InteractionDestroy( interaction_t *p_interaction )
89 {
90     /// \todo Code this, and call it
91 }
92
93 /** 
94  * The main interaction processing loop
95  * This function is called from the playlist loop
96  * 
97  * \param p_playlist the parent playlist
98  * \return nothing
99  */
100 void intf_InteractionManage( playlist_t *p_playlist )
101 {
102     int i_index;
103     interaction_t *p_interaction;
104
105     p_interaction = p_playlist->p_interaction;
106
107     // Nothing to do
108     if( p_interaction->i_dialogs == 0 ) return;
109
110     vlc_mutex_lock( &p_interaction->object_lock );
111
112     intf_InteractionSearchInterface( p_interaction );
113
114     if( !p_interaction->p_intf )
115     {
116         vlc_mutex_unlock( &p_interaction->object_lock );
117
118         /// \todo Remove all dialogs as we can't display them
119         return;
120     }
121
122     vlc_object_yield( p_interaction->p_intf );
123
124     for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
125     {
126         interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index];
127
128         if( p_dialog->b_have_answer )
129         {
130             /// \todo Signal we have an answer
131             // - If have answer, signal what is waiting
132             // (vlc_cond ? dangerous in case of pb ?)
133
134             // Ask interface to hide it
135             p_interaction->p_intf->pf_interact( p_interaction->p_intf,
136                                                 p_dialog, INTERACT_HIDE );
137
138         }
139
140         if( p_dialog->b_updated )
141         {
142             p_dialog->b_finished = VLC_FALSE;
143             p_interaction->p_intf->pf_interact( p_interaction->p_intf,
144                                                 p_dialog, INTERACT_UPDATE );
145         }
146
147         if( p_dialog->b_finished && !p_dialog->b_reusable )
148         {
149             /// \todo Destroy the dialog
150         }
151         // This is truly a new dialog, send it.
152         p_interaction->p_intf->pf_interact( p_interaction->p_intf,
153                                             p_dialog, INTERACT_NEW );
154     }
155
156     vlc_object_release( p_interaction->p_intf );
157
158     vlc_mutex_unlock( &p_playlist->p_interaction->object_lock );
159 }
160
161
162
163 #define INTERACT_INIT( new )                                            \
164         new = (interaction_dialog_t*)malloc(                            \
165                         sizeof( interaction_dialog_t ) );               \
166         new->i_widgets = 0;                                             \
167         new->pp_widgets = NULL;                                         \
168         new->psz_title = NULL;                                          \
169         new->psz_description = NULL;                                    \
170         new->i_id = 0;
171
172 #define INTERACT_FREE( new )                                            \
173         if( new->psz_title ) free( new->psz_title );                    \
174         if( new->psz_description ) free( new->psz_description );
175
176 /** Helper function to send a fatal message
177  *  \param p_this     Parent vlc_object
178  *  \param i_id       A predefined ID, 0 if not applicable
179  *  \param psz_title  Title for the dialog
180  *  \param psz_format The message to display
181  *  */
182 void __intf_UserFatal( vlc_object_t *p_this, int i_id,
183                        const char *psz_title,
184                        const char *psz_format, ... )
185 {
186     va_list args;
187     interaction_dialog_t *p_new = NULL;
188     user_widget_t *p_widget = NULL;
189
190     if( i_id > 0 )
191     {
192         p_new = intf_InteractionGetById( p_this, i_id );
193     }
194     if( !p_new )
195     {
196         INTERACT_INIT( p_new );
197     }
198
199     p_new->i_type = INTERACT_FATAL;
200     p_new->psz_title = strdup( psz_title );
201
202     p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) );
203
204     p_widget->i_type = WIDGET_TEXT;
205
206     va_start( args, psz_format );
207     vasprintf( &p_widget->psz_text, psz_format, args );
208     va_end( args );
209
210     INSERT_ELEM ( p_new->pp_widgets,
211                   p_new->i_widgets,
212                   p_new->i_widgets,
213                   p_widget );
214
215     intf_Interact( p_this, p_new );
216 }
217
218 #if 0
219 /** Helper function to build a progress bar 
220  * \param p_this   Parent vlc object
221  */
222 interaction_dialog_t *__intf_ProgressBuild( vlc_object_t *p_this,
223                                             const char *psz_text )
224 {
225     interaction_dialog_t *p_new = (interaction_dialog_t *)malloc(
226                                         sizeof( interaction_dialog_t ) );
227
228
229     return p_new;
230 }
231 #endif
232
233
234
235 /**********************************************************************
236  * The following functions are local
237  **********************************************************************/
238
239 /* Get the interaction object. Create it if needed */
240 static interaction_t * intf_InteractionGet( vlc_object_t *p_this )
241 {
242     playlist_t *p_playlist;
243     interaction_t *p_interaction;
244
245     p_playlist = (playlist_t*) vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
246                                                 FIND_ANYWHERE );
247
248     if( !p_playlist )
249     {
250         return NULL;
251     }
252
253     if( p_playlist->p_interaction == NULL )
254     {
255         intf_InteractionInit( p_playlist );
256     }
257
258     p_interaction = p_playlist->p_interaction;
259
260     vlc_object_release( p_playlist );
261
262     return p_interaction;
263 }
264
265 /* Create the interaction object in the given playlist object */
266 static void intf_InteractionInit( playlist_t *p_playlist )
267 {
268     interaction_t *p_interaction;
269
270     msg_Dbg( p_playlist, "initializing interaction system" );
271
272     p_interaction = vlc_object_create( VLC_OBJECT( p_playlist ),
273                                        sizeof( interaction_t ) );
274     if( !p_interaction )
275     {
276         msg_Err( p_playlist,"out of memory" );
277         return;
278     }
279
280     p_interaction->i_dialogs = 0;
281     p_interaction->pp_dialogs = NULL;
282     p_interaction->p_intf = NULL;
283     p_interaction->i_last_id = DIALOG_LAST_PREDEFINED + 1;
284
285     vlc_mutex_init( p_interaction , &p_interaction->object_lock );
286
287     p_playlist->p_interaction  = p_interaction;
288 }
289
290 /* Look for an interface suitable for interaction */
291 static void intf_InteractionSearchInterface( interaction_t *p_interaction )
292 {
293     vlc_list_t  *p_list;
294     int          i_index;
295
296     p_interaction->p_intf = NULL;
297
298     p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE );
299     if( !p_list )
300     {
301         msg_Err( p_interaction, "Unable to create module list" );
302         return;
303     }
304
305     for( i_index = 0; i_index < p_list->i_count; i_index ++ )
306     {
307         intf_thread_t *p_intf = (intf_thread_t *)
308                                         p_list->p_values[i_index].p_object;
309         if( p_intf->pf_interact != NULL )
310         {
311             p_interaction->p_intf = p_intf;
312             break;
313         }
314     }
315     vlc_list_release ( p_list );
316 }
317
318 /* Add a dialog to the queue and wait for answer */
319 static int intf_WaitAnswer( interaction_t *p_interact, interaction_dialog_t *p_dialog )
320 {
321     // TODO: Add to queue, wait for answer
322     return VLC_SUCCESS;
323 }
324
325 /* Add a dialog to the queue and return */
326 static int intf_Send( interaction_t *p_interact, interaction_dialog_t *p_dialog )
327 {
328     vlc_mutex_lock( &p_interact->object_lock );
329
330     /// \todo Check first it does not exist !!!
331     INSERT_ELEM( p_interact->pp_dialogs,
332                  p_interact->i_dialogs,
333                  p_interact->i_dialogs,
334                  p_dialog );
335     vlc_mutex_unlock( &p_interact->object_lock );
336     return VLC_SUCCESS;
337 }
338
339 /* Find an interaction dialog by its id */
340 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* p_this,
341                                                        int i_id )
342 {
343     interaction_t *p_interaction = intf_InteractionGet( p_this );
344     int i;
345
346     for( i = 0 ; i< p_interaction->i_dialogs; i++ )
347     {
348         if( p_interaction->pp_dialogs[i]->i_id == i_id )
349         {
350             return p_interaction->pp_dialogs[i];
351         }
352     }
353     return NULL;
354 }