]> git.sesse.net Git - vlc/blob - src/interface/interaction.c
Apparently, someone does not about "make".
[vlc] / src / interface / interaction.c
1 /*****************************************************************************
2  * interaction.c: User interaction functions
3  *****************************************************************************
4  * Copyright (C) 2005-2006 VideoLAN
5  * $Id$
6  *
7  * Authors: Clément Stenac <zorglub@videolan.org>
8  *          Felix Kühne <fkuehne@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /**
26  *   \file
27  *   This file contains functions related to user interaction management
28  */
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <stdlib.h>                                      /* free(), strtol() */
34 #include <stdio.h>                                                   /* FILE */
35 #include <string.h>                                            /* strerror() */
36
37 #include <vlc/vlc.h>
38 #include <vlc/input.h>
39
40 #include "vlc_interaction.h"
41 #include "vlc_interface.h"
42 #include "vlc_playlist.h"
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 static void                  intf_InteractionInit( playlist_t *p_playlist );
48 static interaction_t *       intf_InteractionGet( vlc_object_t *p_this );
49 static void                  intf_InteractionSearchInterface( interaction_t *
50                                                           p_interaction );
51 static int                   intf_WaitAnswer( interaction_t *p_interact,
52                              interaction_dialog_t *p_dialog );
53 static int                   intf_Send( interaction_t *p_interact,
54                              interaction_dialog_t *p_dialog );
55 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* , int );
56 static void                  intf_InteractionDialogDestroy(
57                                               interaction_dialog_t *p_dialog );
58
59 /**
60  * Send an interaction element to the user
61  *
62  * \param p_this the calling vlc_object_t
63  * \param p_interact the interaction element
64  * \return VLC_SUCCESS or an error code
65  */
66 int  __intf_Interact( vlc_object_t *p_this, interaction_dialog_t *p_dialog )
67 {
68     interaction_t *p_interaction = intf_InteractionGet( p_this );
69
70     /* Get an id, if we don't already have one */
71     if( p_dialog->i_id == 0 )
72     {
73         p_dialog->i_id = ++p_interaction->i_last_id;
74     }
75
76     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT ) return VLC_EGENERIC;
77
78     if( config_GetInt(p_this, "interact") || 
79         p_dialog->i_flags & DIALOG_BLOCKING_ERROR ||
80         p_dialog->i_flags & DIALOG_NONBLOCKING_ERROR )
81     {
82         p_dialog->p_interaction = p_interaction;
83         p_dialog->p_parent = p_this;
84
85         if( p_dialog->i_type == INTERACT_DIALOG_TWOWAY )
86         {
87             return intf_WaitAnswer( p_interaction, p_dialog );
88         }
89         else
90         {
91             p_dialog->i_flags |=  DIALOG_GOT_ANSWER;
92             return intf_Send( p_interaction, p_dialog );
93         }
94     }
95     else
96         return VLC_EGENERIC;
97 }
98
99 /**
100  * Destroy the interaction system
101  * \param The interaction object to destroy
102  * \return nothing
103  */
104 void intf_InteractionDestroy( interaction_t *p_interaction )
105 {
106     int i;
107
108     // Remove all dialogs - Interfaces must be able to clean up their data
109
110     for( i = p_interaction->i_dialogs -1 ; i >= 0; i-- )
111     {
112         interaction_dialog_t * p_dialog = p_interaction->pp_dialogs[i];
113         intf_InteractionDialogDestroy( p_dialog );
114         REMOVE_ELEM( p_interaction->pp_dialogs, p_interaction->i_dialogs, i );
115     }
116
117     vlc_object_destroy( p_interaction );
118 }
119
120 /**
121  * The main interaction processing loop
122  * This function is called from the playlist loop
123  *
124  * \param p_playlist the parent playlist
125  * \return nothing
126  */
127 void intf_InteractionManage( playlist_t *p_playlist )
128 {
129     vlc_value_t val;
130     int i_index;
131     interaction_t *p_interaction;
132
133     p_interaction = p_playlist->p_interaction;
134
135     // Nothing to do
136     if( p_interaction->i_dialogs == 0 ) return;
137
138     vlc_mutex_lock( &p_interaction->object_lock );
139
140     intf_InteractionSearchInterface( p_interaction );
141
142     if( !p_interaction->p_intf )
143     {
144         // We mark all dialogs as answered with their "default" answer
145         for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
146         {
147             interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index];
148
149             // Give default answer
150             p_dialog->i_return = DIALOG_DEFAULT;
151
152             // Pretend we have hidden and destroyed it
153             if( p_dialog->i_status == HIDDEN_DIALOG )
154             {
155                 p_dialog->i_status = DESTROYED_DIALOG;
156             }
157             else
158             {
159                 p_dialog->i_status = HIDING_DIALOG;
160             }
161         }
162     }
163     else
164     {
165         vlc_object_yield( p_interaction->p_intf );
166     }
167
168     for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
169     {
170         interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index];
171         switch( p_dialog->i_status )
172         {
173         case ANSWERED_DIALOG:
174             // Ask interface to hide it
175             p_dialog->i_action = INTERACT_HIDE;
176             val.p_address = p_dialog;
177             if( p_interaction->p_intf )
178                 var_Set( p_interaction->p_intf, "interaction", val );
179             p_dialog->i_status = HIDING_DIALOG;
180             break;
181         case UPDATED_DIALOG:
182             p_dialog->i_action = INTERACT_UPDATE;
183             val.p_address = p_dialog;
184             if( p_interaction->p_intf )
185                 var_Set( p_interaction->p_intf, "interaction", val );
186             p_dialog->i_status = SENT_DIALOG;
187             break;
188         case HIDDEN_DIALOG:
189             if( !(p_dialog->i_flags & DIALOG_GOT_ANSWER) ) break;
190             if( !(p_dialog->i_flags & DIALOG_REUSABLE) )
191             {
192                 p_dialog->i_action = INTERACT_DESTROY;
193                 val.p_address = p_dialog;
194                 if( p_interaction->p_intf )
195                     var_Set( p_interaction->p_intf, "interaction", val );
196             }
197             break;
198         case DESTROYED_DIALOG:
199             // Interface has now destroyed it, remove it
200             REMOVE_ELEM( p_interaction->pp_dialogs, p_interaction->i_dialogs,
201                          i_index);
202             i_index--;
203             intf_InteractionDialogDestroy( p_dialog );
204             break;
205         case NEW_DIALOG:
206             // This is truly a new dialog, send it.
207             p_dialog->i_action = INTERACT_NEW;
208             val.p_address = p_dialog;
209             if( p_interaction->p_intf )
210                 var_Set( p_interaction->p_intf, "interaction", val );
211             p_dialog->i_status = SENT_DIALOG;
212             break;
213         }
214     }
215
216     if( p_interaction->p_intf )
217     {
218         vlc_object_release( p_interaction->p_intf );
219     }
220
221     vlc_mutex_unlock( &p_playlist->p_interaction->object_lock );
222 }
223
224
225 #define INTERACT_INIT( new )                                            \
226         new = (interaction_dialog_t*)malloc(                            \
227                         sizeof( interaction_dialog_t ) );               \
228         new->psz_title = NULL;                                          \
229         new->psz_description = NULL;                                    \
230         new->psz_default_button = NULL;                                  \
231         new->psz_alternate_button = NULL;                                \
232         new->psz_other_button = NULL;                                    \
233         new->i_timeToGo = 0;                                            \
234         new->b_cancelled = VLC_FALSE;                                   \
235         new->p_private = NULL;                                          \
236         new->i_id = 0;                                                  \
237         new->i_flags = 0;                                               \
238         new->i_status = NEW_DIALOG;
239
240 #define INTERACT_FREE( new )                                            \
241         if( new->psz_title ) free( new->psz_title );                    \
242         if( new->psz_description ) free( new->psz_description );
243
244 /** Helper function to send an error message, both in a blocking and non-blocking way
245  *  \param p_this     Parent vlc_object
246  *  \param b_blocking Is this dialog blocking or not?
247  *  \param psz_title  Title for the dialog
248  *  \param psz_format The message to display
249  *  */
250 void __intf_UserFatal( vlc_object_t *p_this,
251                        vlc_bool_t b_blocking,
252                        const char *psz_title,
253                        const char *psz_format, ... )
254 {
255     va_list args;
256     interaction_dialog_t *p_new = NULL;
257     
258     INTERACT_INIT( p_new );
259     
260     p_new->psz_title = strdup( psz_title );
261     p_new->i_type = INTERACT_DIALOG_ONEWAY;
262
263     va_start( args, psz_format );
264     vasprintf( &p_new->psz_description, psz_format, args );
265     va_end( args );
266
267     if( b_blocking )
268         p_new->i_flags = DIALOG_BLOCKING_ERROR;
269     else
270         p_new->i_flags = DIALOG_NONBLOCKING_ERROR;
271
272     intf_Interact( p_this, p_new );
273 }
274
275 /** Helper function to send an warning, which is always shown non-blocking
276  *  \param p_this     Parent vlc_object
277  *  \param psz_title  Title for the dialog
278  *  \param psz_format The message to display
279  *  */
280 void __intf_UserWarn( vlc_object_t *p_this,
281                        const char *psz_title,
282                        const char *psz_format, ... )
283 {
284     va_list args;
285     interaction_dialog_t *p_new = NULL;
286     
287     INTERACT_INIT( p_new );
288     
289     p_new->psz_title = strdup( psz_title );
290     p_new->i_type = INTERACT_DIALOG_ONEWAY;
291
292     va_start( args, psz_format );
293     vasprintf( &p_new->psz_description, psz_format, args );
294     va_end( args );
295
296     p_new->i_flags = DIALOG_WARNING;
297
298     intf_Interact( p_this, p_new );
299 }
300
301 /** Helper function to ask a yes-no-cancel question
302  *  \param p_this           Parent vlc_object
303  *  \param psz_title        Title for the dialog
304  *  \param psz_description  A description
305  *  \param psz_default      caption for the default button
306  *  \param psz_alternate    caption for the alternate button
307  *  \param psz_other        caption for the optional 3rd button (== cancel)
308  *  \return                 Clicked button code
309  */
310 int __intf_UserYesNo( vlc_object_t *p_this,
311                       const char *psz_title,
312                       const char *psz_description,
313                       const char *psz_default,
314                       const char *psz_alternate,
315                       const char *psz_other )
316 {
317     int i_ret;
318     interaction_dialog_t *p_new = NULL;
319
320     INTERACT_INIT( p_new );
321
322     p_new->i_type = INTERACT_DIALOG_TWOWAY;
323     p_new->psz_title = strdup( psz_title );
324     p_new->psz_description = strdup( psz_description );
325     p_new->i_flags = DIALOG_YES_NO_CANCEL;
326     p_new->psz_default_button = strdup( psz_default );
327     p_new->psz_alternate_button = strdup( psz_alternate );
328     if( psz_other )
329         p_new->psz_other_button = strdup( psz_other );
330     else
331         p_new->psz_other_button = NULL;
332
333     i_ret = intf_Interact( p_this, p_new );
334
335     return i_ret;
336 }
337
338 /** Helper function to create a dialogue showing a progress-bar with some info
339  *  \param p_this           Parent vlc_object
340  *  \param psz_title        Title for the dialog
341  *  \param psz_status       Current status
342  *  \param f_position       Current position (0.0->100.0)
343  *  \param i_timeToGo       Time (in sec) to go until process is finished
344  *  \return                 Dialog id, to give to UserProgressUpdate
345  */
346 int __intf_UserProgress( vlc_object_t *p_this,
347                          const char *psz_title,
348                          const char *psz_status,
349                          float f_pos,
350                          int i_time )
351 {
352     int i_ret;
353     interaction_dialog_t *p_new = NULL;
354
355     INTERACT_INIT( p_new );
356
357     p_new->i_type = INTERACT_DIALOG_ONEWAY;
358     p_new->psz_title = strdup( psz_title );
359     p_new->psz_description = strdup( psz_status );
360     p_new->val.f_float = f_pos;
361     p_new->i_timeToGo = i_time;
362
363     p_new->i_flags = DIALOG_USER_PROGRESS;
364
365     i_ret = intf_Interact( p_this, p_new );
366
367     return p_new->i_id;
368 }
369
370 /** Update a progress bar in a dialogue
371  *  \param p_this           Parent vlc_object
372  *  \param i_id             Identifier of the dialog
373  *  \param psz_status       New status
374  *  \param f_position       New position (0.0->100.0)
375  *  \param i_timeToGo       Time (in sec) to go until process is finished
376  *  \return                 nothing
377  */
378 void __intf_UserProgressUpdate( vlc_object_t *p_this, int i_id,
379                                 const char *psz_status, float f_pos, 
380                                 int i_time )
381 {
382     interaction_t *p_interaction = intf_InteractionGet( p_this );
383     interaction_dialog_t *p_dialog;
384
385     if( !p_interaction ) return;
386
387     vlc_mutex_lock( &p_interaction->object_lock );
388     p_dialog  =  intf_InteractionGetById( p_this, i_id );
389
390     if( !p_dialog )
391     {
392         vlc_mutex_unlock( &p_interaction->object_lock ) ;
393         return;
394     }
395
396     if( p_dialog->psz_description )
397         free( p_dialog->psz_description );
398     p_dialog->psz_description = strdup( psz_status );
399
400     p_dialog->val.f_float = f_pos;
401     p_dialog->i_timeToGo = i_time;
402
403     p_dialog->i_status = UPDATED_DIALOG;
404     vlc_mutex_unlock( &p_interaction->object_lock) ;
405 }
406
407 /** Helper function to communicate dialogue cancellations between the intf-module and caller
408  *  \param p_this           Parent vlc_object
409  *  \param i_id             Identifier of the dialogue
410  *  \return                 Either true or false
411  */
412 vlc_bool_t __intf_UserProgressIsCancelled( vlc_object_t *p_this, int i_id )
413 {
414     interaction_t *p_interaction = intf_InteractionGet( p_this );
415     interaction_dialog_t *p_dialog;
416
417     if( !p_interaction ) return VLC_TRUE;
418
419     vlc_mutex_lock( &p_interaction->object_lock );
420     p_dialog  =  intf_InteractionGetById( p_this, i_id );
421
422     if( !p_dialog )
423     {
424         vlc_mutex_unlock( &p_interaction->object_lock ) ;
425         return VLC_TRUE;
426     }
427
428     vlc_mutex_unlock( &p_interaction->object_lock) ;
429     return p_dialog->b_cancelled;
430 }
431
432 /** Helper function to make a login/password dialogue
433  *  \param p_this           Parent vlc_object
434  *  \param psz_title        Title for the dialog
435  *  \param psz_description  A description
436  *  \param ppsz_login       Returned login
437  *  \param ppsz_password    Returned password
438  *  \return                 Clicked button code
439  */
440 int __intf_UserLoginPassword( vlc_object_t *p_this,
441                               const char *psz_title,
442                               const char *psz_description,
443                               char **ppsz_login,
444                               char **ppsz_password )
445 {
446
447     int i_ret;
448     interaction_dialog_t *p_new = NULL;
449
450     INTERACT_INIT( p_new );
451
452     p_new->i_type = INTERACT_DIALOG_TWOWAY;
453     p_new->psz_title = strdup( psz_title );
454     p_new->psz_description = strdup( psz_description );
455
456     p_new->i_flags = DIALOG_LOGIN_PW_OK_CANCEL;
457
458     i_ret = intf_Interact( p_this, p_new );
459
460     if( i_ret != DIALOG_CANCELLED )
461     {
462         *ppsz_login = strdup( p_new->psz_returned[0] );
463         *ppsz_password = strdup( p_new->psz_returned[1] );
464     }
465     return i_ret;
466 }
467
468 /** Helper function to make a dialogue asking the user for !password string
469  *  \param p_this           Parent vlc_object
470  *  \param psz_title        Title for the dialog
471  *  \param psz_description  A description
472  *  \param ppsz_usersString Returned login
473  *  \return                 Clicked button code
474  */
475 int __intf_UserStringInput( vlc_object_t *p_this,
476                               const char *psz_title,
477                               const char *psz_description,
478                               char **ppsz_usersString )
479 {
480
481     int i_ret;
482     interaction_dialog_t *p_new = NULL;
483
484     INTERACT_INIT( p_new );
485
486     p_new->i_type = INTERACT_DIALOG_TWOWAY;
487     p_new->psz_title = strdup( psz_title );
488     p_new->psz_description = strdup( psz_description );
489
490     p_new->i_flags = DIALOG_PSZ_INPUT_OK_CANCEL;
491
492     i_ret = intf_Interact( p_this, p_new );
493
494     if( i_ret != DIALOG_CANCELLED )
495     {
496         *ppsz_usersString = strdup( p_new->psz_returned[0] );
497     }
498     return i_ret;
499 }
500
501 /** Helper function to create a progress-bar in the main interface with a
502  *  single-line description
503  *  \param p_this           Parent vlc_object
504  *  \param psz_status       Current status
505  *  \param f_position       Current position (0.0->100.0)
506  *  \return                 Dialog id, to give to IntfProgressUpdate
507  */
508 int __intf_IntfProgress( vlc_object_t *p_this,
509                          const char *psz_status,
510                          float f_pos )
511 {
512     int i_ret;
513     interaction_dialog_t *p_new = NULL;
514
515     INTERACT_INIT( p_new );
516
517     p_new->i_type = INTERACT_DIALOG_ONEWAY;
518     p_new->psz_description = strdup( psz_status );
519     p_new->val.f_float = f_pos;
520
521     p_new->i_flags = DIALOG_INTF_PROGRESS;
522
523     i_ret = intf_Interact( p_this, p_new );
524
525     return p_new->i_id;
526 }
527
528 /** Update the progress bar in the main interface
529  *  \param p_this           Parent vlc_object
530  *  \param i_id             Identifier of the dialog
531  *  \param psz_status       New status
532  *  \param f_position       New position (0.0->100.0)
533  *  \return                 nothing
534  */
535 void __intf_IntfProgressUpdate( vlc_object_t *p_this, int i_id,
536                                 const char *psz_status, float f_pos )
537 {
538     interaction_t *p_interaction = intf_InteractionGet( p_this );
539     interaction_dialog_t *p_dialog;
540
541     if( !p_interaction ) return;
542
543     vlc_mutex_lock( &p_interaction->object_lock );
544     p_dialog  =  intf_InteractionGetById( p_this, i_id );
545
546     if( !p_dialog )
547     {
548         vlc_mutex_unlock( &p_interaction->object_lock ) ;
549         return;
550     }
551
552     if( p_dialog->psz_description )
553         free( p_dialog->psz_description );
554     p_dialog->psz_description = strdup( psz_status );
555
556     p_dialog->val.f_float = f_pos;
557
558     p_dialog->i_status = UPDATED_DIALOG;
559     vlc_mutex_unlock( &p_interaction->object_lock) ;
560 }
561
562 /** Hide an interaction dialog
563  * \param p_this the parent vlc object
564  * \param i_id the id of the item to hide
565  * \return nothing
566  */
567 void __intf_UserHide( vlc_object_t *p_this, int i_id )
568 {
569     interaction_t *p_interaction = intf_InteractionGet( p_this );
570     interaction_dialog_t *p_dialog;
571
572     if( !p_interaction ) return;
573
574     vlc_mutex_lock( &p_interaction->object_lock );
575     p_dialog  =  intf_InteractionGetById( p_this, i_id );
576
577     if( !p_dialog )
578     {
579        vlc_mutex_unlock( &p_interaction->object_lock );
580        return;
581     }
582
583     p_dialog->i_status = ANSWERED_DIALOG;
584     vlc_mutex_unlock( &p_interaction->object_lock );
585 }
586
587
588
589 /**********************************************************************
590  * The following functions are local
591  **********************************************************************/
592
593 /* Get the interaction object. Create it if needed */
594 static interaction_t * intf_InteractionGet( vlc_object_t *p_this )
595 {
596     playlist_t *p_playlist;
597     interaction_t *p_interaction;
598
599     p_playlist = (playlist_t*) vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
600                                                 FIND_ANYWHERE );
601
602     if( !p_playlist )
603     {
604         return NULL;
605     }
606
607     if( p_playlist->p_interaction == NULL )
608     {
609         intf_InteractionInit( p_playlist );
610     }
611
612     p_interaction = p_playlist->p_interaction;
613
614     vlc_object_release( p_playlist );
615
616     return p_interaction;
617 }
618
619 /* Create the interaction object in the given playlist object */
620 static void intf_InteractionInit( playlist_t *p_playlist )
621 {
622     interaction_t *p_interaction;
623
624     p_interaction = vlc_object_create( VLC_OBJECT( p_playlist ),
625                                        sizeof( interaction_t ) );
626     if( !p_interaction )
627     {
628         msg_Err( p_playlist,"out of memory" );
629         return;
630     }
631
632     p_interaction->i_dialogs = 0;
633     p_interaction->pp_dialogs = NULL;
634     p_interaction->p_intf = NULL;
635     p_interaction->i_last_id = DIALOG_LAST_PREDEFINED + 1;
636
637     vlc_mutex_init( p_interaction , &p_interaction->object_lock );
638
639     p_playlist->p_interaction  = p_interaction;
640 }
641
642 /* Look for an interface suitable for interaction */
643 static void intf_InteractionSearchInterface( interaction_t *p_interaction )
644 {
645     vlc_list_t  *p_list;
646     int          i_index;
647
648     p_interaction->p_intf = NULL;
649
650     p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE );
651     if( !p_list )
652     {
653         msg_Err( p_interaction, "unable to create module list" );
654         return;
655     }
656
657     for( i_index = 0; i_index < p_list->i_count; i_index ++ )
658     {
659         intf_thread_t *p_intf = (intf_thread_t *)
660                                         p_list->p_values[i_index].p_object;
661         if( p_intf->b_interaction )
662         {
663             p_interaction->p_intf = p_intf;
664             break;
665         }
666     }
667     vlc_list_release ( p_list );
668 }
669
670 /* Add a dialog to the queue and wait for answer */
671 static int intf_WaitAnswer( interaction_t *p_interact,
672                             interaction_dialog_t *p_dialog )
673 {
674     int i;
675     vlc_bool_t b_found = VLC_FALSE;
676     vlc_mutex_lock( &p_interact->object_lock );
677     for( i = 0 ; i< p_interact->i_dialogs; i++ )
678     {
679         if( p_interact->pp_dialogs[i]->i_id == p_dialog->i_id )
680         {
681             b_found = VLC_TRUE;
682         }
683     }
684     if( ! b_found )
685     {
686         INSERT_ELEM( p_interact->pp_dialogs,
687                      p_interact->i_dialogs,
688                      p_interact->i_dialogs,
689                      p_dialog );
690     }
691     else
692         p_dialog->i_status = UPDATED_DIALOG;
693     vlc_mutex_unlock( &p_interact->object_lock );
694
695     /// \todo Check that the initiating object is not dying
696     while( p_dialog->i_status != ANSWERED_DIALOG &&
697            p_dialog->i_status != HIDING_DIALOG &&
698            p_dialog->i_status != HIDDEN_DIALOG &&
699            !p_dialog->p_parent->b_die )
700     {
701         msleep( 100000 );
702     }
703     /// \todo locking
704     if( p_dialog->p_parent->b_die )
705     {
706         p_dialog->i_return = DIALOG_CANCELLED;
707         p_dialog->i_status = ANSWERED_DIALOG;
708     }
709     p_dialog->i_flags |= DIALOG_GOT_ANSWER;
710     return p_dialog->i_return;
711 }
712
713 /* Add a dialog to the queue and return */
714 static int intf_Send( interaction_t *p_interact,
715                       interaction_dialog_t *p_dialog )
716 {
717     int i;
718     vlc_bool_t b_found = VLC_FALSE;
719     if( p_interact == NULL ) return VLC_ENOOBJ;
720     vlc_mutex_lock( &p_interact->object_lock );
721
722     for( i = 0 ; i< p_interact->i_dialogs; i++ )
723     {
724         if( p_interact->pp_dialogs[i]->i_id == p_dialog->i_id )
725         {
726             b_found = VLC_TRUE;
727         }
728     }
729     if( !b_found )
730     {
731         INSERT_ELEM( p_interact->pp_dialogs,
732                      p_interact->i_dialogs,
733                      p_interact->i_dialogs,
734                      p_dialog );
735     }
736     else
737         p_dialog->i_status = UPDATED_DIALOG;
738     // Pretend we already retrieved the "answer"
739     p_dialog->i_flags |= DIALOG_GOT_ANSWER;
740     vlc_mutex_unlock( &p_interact->object_lock );
741     return VLC_SUCCESS;
742 }
743
744 /* Find an interaction dialog by its id */
745 static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* p_this,
746                                                        int i_id )
747 {
748     interaction_t *p_interaction = intf_InteractionGet( p_this );
749     int i;
750
751     if( !p_interaction ) return NULL;
752
753     for( i = 0 ; i< p_interaction->i_dialogs; i++ )
754     {
755         if( p_interaction->pp_dialogs[i]->i_id == i_id )
756         {
757             return p_interaction->pp_dialogs[i];
758         }
759     }
760     return NULL;
761 }
762
763 #define FREE( i ) { if( i ) free( i ); i = NULL; }
764
765 static void intf_InteractionDialogDestroy( interaction_dialog_t *p_dialog )
766 {
767     FREE( p_dialog->psz_title );
768     FREE( p_dialog->psz_description );
769     FREE( p_dialog->psz_default_button );
770     FREE( p_dialog->psz_alternate_button );
771     FREE( p_dialog->psz_other_button );
772
773     free( p_dialog );
774 }