]> git.sesse.net Git - vlc/blob - src/interface/interaction.c
Replace function callback by variable callback.
[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     vlc_value_t val;
103     int i_index;
104     interaction_t *p_interaction;
105
106     p_interaction = p_playlist->p_interaction;
107
108     // Nothing to do
109     if( p_interaction->i_dialogs == 0 ) return;
110
111     vlc_mutex_lock( &p_interaction->object_lock );
112
113     intf_InteractionSearchInterface( p_interaction );
114
115     if( !p_interaction->p_intf )
116     {
117         vlc_mutex_unlock( &p_interaction->object_lock );
118
119         /// \todo Remove all dialogs as we can't display them
120         return;
121     }
122
123     vlc_object_yield( p_interaction->p_intf );
124
125     for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
126     {
127         interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index];
128
129         switch( p_dialog->i_status )
130         {
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 ?)
135
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;
142             break;
143         case UPDATED_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 );
150             break;
151         case HIDDEN_DIALOG:
152             if( !p_dialog->b_reusable )
153             {
154                 /// \todo Destroy the dialog
155             }
156             break;
157         case NEW_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;
165             break;
166         }
167     }
168
169     vlc_object_release( p_interaction->p_intf );
170
171     vlc_mutex_unlock( &p_playlist->p_interaction->object_lock );
172 }
173
174
175
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;                                    \
183         new->i_id = 0;                                                  \
184         new->i_status = NEW_DIALOG;
185
186 #define INTERACT_FREE( new )                                            \
187         if( new->psz_title ) free( new->psz_title );                    \
188         if( new->psz_description ) free( new->psz_description );
189
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
195  *  */
196 void __intf_UserFatal( vlc_object_t *p_this, int i_id,
197                        const char *psz_title,
198                        const char *psz_format, ... )
199 {
200     va_list args;
201     interaction_dialog_t *p_new = NULL;
202     user_widget_t *p_widget = NULL;
203
204     if( i_id > 0 )
205     {
206         p_new = intf_InteractionGetById( p_this, i_id );
207     }
208     if( !p_new )
209     {
210         INTERACT_INIT( p_new );
211         if( i_id > 0 ) p_new->i_id = i_id ;
212     }
213     else
214     {
215         p_new->i_status = UPDATED_DIALOG;
216     }
217
218     p_new->i_type = INTERACT_FATAL;
219     p_new->psz_title = strdup( psz_title );
220
221     p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) );
222
223     p_widget->i_type = WIDGET_TEXT;
224
225     va_start( args, psz_format );
226     vasprintf( &p_widget->psz_text, psz_format, args );
227     va_end( args );
228
229     INSERT_ELEM ( p_new->pp_widgets,
230                   p_new->i_widgets,
231                   p_new->i_widgets,
232                   p_widget );
233
234     intf_Interact( p_this, p_new );
235 }
236
237 #if 0
238 /** Helper function to build a progress bar
239  * \param p_this   Parent vlc object
240  */
241 interaction_dialog_t *__intf_ProgressBuild( vlc_object_t *p_this,
242                                             const char *psz_text )
243 {
244     interaction_dialog_t *p_new = (interaction_dialog_t *)malloc(
245                                         sizeof( interaction_dialog_t ) );
246
247
248     return p_new;
249 }
250 #endif
251
252
253
254 /**********************************************************************
255  * The following functions are local
256  **********************************************************************/
257
258 /* Get the interaction object. Create it if needed */
259 static interaction_t * intf_InteractionGet( vlc_object_t *p_this )
260 {
261     playlist_t *p_playlist;
262     interaction_t *p_interaction;
263
264     p_playlist = (playlist_t*) vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
265                                                 FIND_ANYWHERE );
266
267     if( !p_playlist )
268     {
269         return NULL;
270     }
271
272     if( p_playlist->p_interaction == NULL )
273     {
274         intf_InteractionInit( p_playlist );
275     }
276
277     p_interaction = p_playlist->p_interaction;
278
279     vlc_object_release( p_playlist );
280
281     return p_interaction;
282 }
283
284 /* Create the interaction object in the given playlist object */
285 static void intf_InteractionInit( playlist_t *p_playlist )
286 {
287     interaction_t *p_interaction;
288
289     msg_Dbg( p_playlist, "initializing interaction system" );
290
291     p_interaction = vlc_object_create( VLC_OBJECT( p_playlist ),
292                                        sizeof( interaction_t ) );
293     if( !p_interaction )
294     {
295         msg_Err( p_playlist,"out of memory" );
296         return;
297     }
298
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;
303
304     vlc_mutex_init( p_interaction , &p_interaction->object_lock );
305
306     p_playlist->p_interaction  = p_interaction;
307 }
308
309 /* Look for an interface suitable for interaction */
310 static void intf_InteractionSearchInterface( interaction_t *p_interaction )
311 {
312     vlc_list_t  *p_list;
313     int          i_index;
314
315     p_interaction->p_intf = NULL;
316
317     p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE );
318     if( !p_list )
319     {
320         msg_Err( p_interaction, "Unable to create module list" );
321         return;
322     }
323
324     for( i_index = 0; i_index < p_list->i_count; i_index ++ )
325     {
326         intf_thread_t *p_intf = (intf_thread_t *)
327                                         p_list->p_values[i_index].p_object;
328         if( p_intf->b_interaction )
329         {
330             p_interaction->p_intf = p_intf;
331             break;
332         }
333     }
334     vlc_list_release ( p_list );
335 }
336
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 )
339 {
340     // TODO: Add to queue, wait for answer
341     return VLC_SUCCESS;
342 }
343
344 /* Add a dialog to the queue and return */
345 static int intf_Send( interaction_t *p_interact, interaction_dialog_t *p_dialog )
346 {
347     vlc_mutex_lock( &p_interact->object_lock );
348
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,
353                  p_dialog );
354     vlc_mutex_unlock( &p_interact->object_lock );
355     return VLC_SUCCESS;
356 }
357
358 /* Find an interaction dialog by its id */
359 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* p_this,
360                                                        int i_id )
361 {
362     interaction_t *p_interaction = intf_InteractionGet( p_this );
363     int i;
364
365     for( i = 0 ; i< p_interaction->i_dialogs; i++ )
366     {
367         if( p_interaction->pp_dialogs[i]->i_id == i_id )
368         {
369             return p_interaction->pp_dialogs[i];
370         }
371     }
372     return NULL;
373 }