Changeset 55f3a9f1dc708d536a61a8f65c8b3c854c14e360

Show
Ignore:
Timestamp:
03/16/08 20:50:21 (6 months ago)
Author:
Rafaël Carré <funman@videolan.org>
git-committer:
Rafaël Carré <funman@videolan.org> 1205697021 +0100
git-parent:

[f0c27947efb2fab7144ffd3425e3822d6073d622]

git-author:
Rafaël Carré <funman@videolan.org> 1205696966 +0100
Message:

Interaction are controlled by a dedicated thread

This is not the playlist's work at all
Fix #1520

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • extras/buildsystem/cmake/CMakeLists/src_CMakeLists.txt

    rd8ff00d r55f3a9f  
    2121    libvlc.h 
    2222    libvlc-module.c 
    23     interface/interface.h 
    2423    interface/interface.c 
    2524    interface/intf_eject.c 
  • include/vlc_objects.h

    ra78e273 r55f3a9f  
    6868#define VLC_OBJECT_HTTPD_HOST  (-30) 
    6969#define VLC_OBJECT_META_ENGINE (-31) 
     70#define VLC_OBJECT_INTERACTION (-32) 
    7071 
    7172#define VLC_OBJECT_GENERIC     (-666) 
  • include/vlc_playlist.h

    rb056504 r55f3a9f  
    238238 
    239239    // Playlist-unrelated fields 
    240     interaction_t       *p_interaction;    /**< Interaction manager */ 
    241240    input_thread_t      *p_stats_computer; /**< Input thread computing stats */ 
    242241    global_stats_t      *p_stats;          /**< Global statistics */ 
  • src/Makefile.am

    r10fd1f1 r55f3a9f  
    236236    libvlc.h \ 
    237237    libvlc-module.c \ 
    238     interface/interface.h \ 
    239238    interface/interface.c \ 
    240239    interface/intf_eject.c \ 
  • src/interface/interaction.c

    r7ad4142 r55f3a9f  
    22 * interaction.c: User interaction functions 
    33 ***************************************************************************** 
    4  * Copyright (C) 2005-2006 the VideoLAN team 
     4 * Copyright © 2005-2008 the VideoLAN team 
    55 * $Id$ 
    66 * 
     
    3838#include <vlc/vlc.h> 
    3939 
    40 #include <stdlib.h>                                      /* free(), strtol() */ 
    41 #include <stdio.h>                                                   /* FILE */ 
    42 #include <string.h> 
    43  
    4440#include <vlc_interface.h> 
    45 #include <vlc_playlist.h> 
    46 #include "interface.h" 
    4741 
    4842/***************************************************************************** 
    4943 * Local prototypes 
    5044 *****************************************************************************/ 
    51 static void                  InteractionInit( playlist_t *p_playlist ); 
    52 static interaction_t *       InteractionGet( vlc_object_t *p_this ); 
    53 static void                  InteractionSearchInterface( interaction_t * 
    54                                                           p_interaction ); 
    55 static interaction_dialog_t *DialogGetById( interaction_t* , int ); 
    56 static void                  DialogDestroy( interaction_dialog_t *p_dialog ); 
    57 static int DialogSend( vlc_object_t *p_this, interaction_dialog_t *p_dialog ); 
    58  
    59 /** 
    60  * Destroy the interaction system 
    61  * 
    62  * \param The interaction object to destroy 
     45static interaction_t *          InteractionInit( libvlc_int_t * ); 
     46static interaction_t *          InteractionGet( vlc_object_t * ); 
     47static void                     InteractionSearchInterface( interaction_t * ); 
     48static void                     InteractionLoop( vlc_object_t * ); 
     49static void                     InteractionManage( interaction_t * ); 
     50 
     51static interaction_dialog_t    *DialogGetById( interaction_t* , int ); 
     52static void                     DialogDestroy( interaction_dialog_t * ); 
     53static int DialogSend( vlc_object_t *, interaction_dialog_t * ); 
     54 
     55#define DIALOG_INIT( type ) \ 
     56        DECMALLOC_ERR( p_new, interaction_dialog_t );       \ 
     57        memset( p_new, 0, sizeof( interaction_dialog_t ) ); \ 
     58        p_new->b_cancelled = VLC_FALSE;                     \ 
     59        p_new->i_status = NEW_DIALOG;                       \ 
     60        p_new->i_flags = 0;                                 \ 
     61        p_new->i_type = INTERACT_DIALOG_##type;             \ 
     62        p_new->psz_returned[0] = NULL;                      \ 
     63        p_new->psz_returned[1] = NULL 
     64 
     65#define FORMAT_DESC \ 
     66        va_start( args, psz_format ); \ 
     67        if( vasprintf( &p_new->psz_description, psz_format, args ) == -1 ) \ 
     68            return VLC_EGENERIC; \ 
     69        va_end( args ) 
     70 
     71/** 
     72 * Send an error message, both in a blocking and non-blocking way 
     73 * 
     74 * \param p_this     Parent vlc_object 
     75 * \param b_blocking Is this dialog blocking or not? 
     76 * \param psz_title  Title for the dialog 
     77 * \param psz_format The message to display 
     78 * \return           VLC_SUCCESS or VLC_EGENERIC 
     79 */ 
     80int __intf_UserFatal( vlc_object_t *p_this, vlc_bool_t b_blocking, 
     81                       const char *psz_title, 
     82                       const char *psz_format, ... ) 
     83
     84    va_list args; 
     85    DIALOG_INIT( ONEWAY ); 
     86 
     87    p_new->psz_title = strdup( psz_title ); 
     88    FORMAT_DESC; 
     89 
     90    if( b_blocking ) 
     91        p_new->i_flags = DIALOG_BLOCKING_ERROR; 
     92    else 
     93        p_new->i_flags = DIALOG_NONBLOCKING_ERROR; 
     94 
     95    return DialogSend( p_this, p_new ); 
     96
     97 
     98/** 
     99 * Helper function to send a warning, which is always shown non-blocking 
     100 * 
     101 * \param p_this     Parent vlc_object 
     102 * \param psz_title  Title for the dialog 
     103 * \param psz_format The message to display 
     104 * \return           VLC_SUCCESS or VLC_EGENERIC 
     105 */ 
     106int __intf_UserWarn( vlc_object_t *p_this, 
     107                     const char *psz_title, 
     108                     const char *psz_format, ... ) 
     109
     110    va_list args; 
     111    DIALOG_INIT( ONEWAY ); 
     112 
     113    p_new->psz_title = strdup( psz_title ); 
     114    FORMAT_DESC; 
     115 
     116    p_new->i_flags = DIALOG_WARNING; 
     117 
     118    return DialogSend( p_this, p_new ); 
     119
     120 
     121/** 
     122 * Helper function to ask a yes-no-cancel question 
     123 * 
     124 * \param p_this           Parent vlc_object 
     125 * \param psz_title        Title for the dialog 
     126 * \param psz_description  A description 
     127 * \param psz_default      caption for the default button 
     128 * \param psz_alternate    caption for the alternate button 
     129 * \param psz_other        caption for the optional 3rd button (== cancel) 
     130 * \return                 Clicked button code 
     131 */ 
     132int __intf_UserYesNo( vlc_object_t *p_this, 
     133                      const char *psz_title, 
     134                      const char *psz_description, 
     135                      const char *psz_default, 
     136                      const char *psz_alternate, 
     137                      const char *psz_other ) 
     138
     139    DIALOG_INIT( TWOWAY ); 
     140 
     141    p_new->psz_title = strdup( psz_title ); 
     142    p_new->psz_description = strdup( psz_description ); 
     143    p_new->i_flags = DIALOG_YES_NO_CANCEL; 
     144    p_new->psz_default_button = strdup( psz_default ); 
     145    p_new->psz_alternate_button = strdup( psz_alternate ); 
     146    if( psz_other ) 
     147        p_new->psz_other_button = strdup( psz_other ); 
     148 
     149    return DialogSend( p_this, p_new ); 
     150
     151 
     152/** 
     153 * Helper function to create a dialogue showing a progress-bar with some info 
     154 * 
     155 * \param p_this           Parent vlc_object 
     156 * \param psz_title        Title for the dialog (NULL implies main intf ) 
     157 * \param psz_status       Current status 
     158 * \param f_position       Current position (0.0->100.0) 
     159 * \param i_timeToGo       Time (in sec) to go until process is finished 
     160 * \return                 Dialog id, to give to UserProgressUpdate 
     161 */ 
     162int __intf_Progress( vlc_object_t *p_this, const char *psz_title, 
     163                     const char *psz_status, float f_pos, int i_time ) 
     164
     165    DIALOG_INIT( ONEWAY ); 
     166    p_new->psz_description = strdup( psz_status ); 
     167    p_new->val.f_float = f_pos; 
     168    p_new->i_timeToGo = i_time; 
     169    p_new->psz_alternate_button = strdup( _( "Cancel" ) ); 
     170 
     171    if( psz_title ) 
     172    { 
     173        p_new->psz_title = strdup( psz_title ); 
     174        p_new->i_flags = DIALOG_USER_PROGRESS; 
     175    } 
     176    else 
     177        p_new->i_flags = DIALOG_INTF_PROGRESS; 
     178 
     179    DialogSend( p_this, p_new ); 
     180    return p_new->i_id; 
     181
     182 
     183/** 
     184 * Update a progress bar in a dialogue 
     185 * 
     186 * \param p_this           Parent vlc_object 
     187 * \param i_id             Identifier of the dialog 
     188 * \param psz_status       New status 
     189 * \param f_position       New position (0.0->100.0) 
     190 * \param i_timeToGo       Time (in sec) to go until process is finished 
     191 * \return                 nothing 
     192 */ 
     193void __intf_ProgressUpdate( vlc_object_t *p_this, int i_id, 
     194                            const char *psz_status, float f_pos, int i_time ) 
     195
     196    interaction_t *p_interaction = InteractionGet( p_this ); 
     197    interaction_dialog_t *p_dialog; 
     198 
     199    if( !p_interaction ) return; 
     200 
     201    vlc_object_lock( p_interaction ); 
     202    p_dialog  =  DialogGetById( p_interaction, i_id ); 
     203 
     204    if( !p_dialog ) 
     205    { 
     206        vlc_object_unlock( p_interaction ); 
     207        vlc_object_release( p_interaction ); 
     208        return; 
     209    } 
     210 
     211    free( p_dialog->psz_description ); 
     212    p_dialog->psz_description = strdup( psz_status ); 
     213 
     214    p_dialog->val.f_float = f_pos; 
     215    p_dialog->i_timeToGo = i_time; 
     216 
     217    p_dialog->i_status = UPDATED_DIALOG; 
     218 
     219    vlc_object_signal_unlocked( p_interaction ); 
     220    vlc_object_unlock( p_interaction ); 
     221    vlc_object_release( p_interaction ); 
     222
     223 
     224/** 
     225 * Helper function to communicate dialogue cancellations between the 
     226 * interface module and the caller 
     227 * 
     228 * \param p_this           Parent vlc_object 
     229 * \param i_id             Identifier of the dialogue 
     230 * \return                 Either true or false 
     231 */ 
     232vlc_bool_t __intf_UserProgressIsCancelled( vlc_object_t *p_this, int i_id ) 
     233
     234    interaction_t *p_interaction = InteractionGet( p_this ); 
     235    interaction_dialog_t *p_dialog; 
     236    vlc_bool_t b_cancel; 
     237 
     238    if( !p_interaction ) return VLC_TRUE; 
     239 
     240    vlc_object_lock( p_interaction ); 
     241    p_dialog  =  DialogGetById( p_interaction, i_id ); 
     242    if( !p_dialog ) 
     243    { 
     244        vlc_object_unlock( p_interaction ) ; 
     245        vlc_object_release( p_interaction ); 
     246        return VLC_TRUE; 
     247    } 
     248 
     249    b_cancel = p_dialog->b_cancelled; 
     250    vlc_object_unlock( p_interaction ); 
     251    vlc_object_release( p_interaction ); 
     252    return b_cancel; 
     253
     254 
     255/** 
     256 * Helper function to make a login/password dialogue 
     257 * 
     258 * \param p_this           Parent vlc_object 
     259 * \param psz_title        Title for the dialog 
     260 * \param psz_description  A description 
     261 * \param ppsz_login       Returned login 
     262 * \param ppsz_password    Returned password 
     263 * \return                 Clicked button code 
     264 */ 
     265int __intf_UserLoginPassword( vlc_object_t *p_this, 
     266        const char *psz_title, 
     267        const char *psz_description, 
     268        char **ppsz_login, 
     269        char **ppsz_password ) 
     270
     271    int i_ret; 
     272    DIALOG_INIT( TWOWAY ); 
     273    p_new->i_type = INTERACT_DIALOG_TWOWAY; 
     274    p_new->psz_title = strdup( psz_title ); 
     275    p_new->psz_description = strdup( psz_description ); 
     276    p_new->psz_default_button = strdup( _("Ok" ) ); 
     277    p_new->psz_alternate_button = strdup( _("Cancel" ) ); 
     278 
     279    p_new->i_flags = DIALOG_LOGIN_PW_OK_CANCEL; 
     280 
     281    i_ret = DialogSend( p_this, p_new ); 
     282 
     283    if( i_ret != DIALOG_CANCELLED && i_ret != VLC_EGENERIC ) 
     284    { 
     285        *ppsz_login = p_new->psz_returned[0]? 
     286            strdup( p_new->psz_returned[0] ) : NULL; 
     287        *ppsz_password = p_new->psz_returned[1]? 
     288            strdup( p_new->psz_returned[1] ) : NULL; 
     289    } 
     290    return i_ret; 
     291
     292 
     293/** 
     294 * Helper function to make a dialogue asking the user for !password string 
     295 * 
     296 * \param p_this           Parent vlc_object 
     297 * \param psz_title        Title for the dialog 
     298 * \param psz_description  A description 
     299 * \param ppsz_usersString Returned login 
     300 * \return                 Clicked button code 
     301 */ 
     302int __intf_UserStringInput( vlc_object_t *p_this, 
     303        const char *psz_title, 
     304        const char *psz_description, 
     305        char **ppsz_usersString ) 
     306
     307    int i_ret; 
     308    DIALOG_INIT( TWOWAY ); 
     309    p_new->i_type = INTERACT_DIALOG_TWOWAY; 
     310    p_new->psz_title = strdup( psz_title ); 
     311    p_new->psz_description = strdup( psz_description ); 
     312 
     313    p_new->i_flags = DIALOG_PSZ_INPUT_OK_CANCEL; 
     314 
     315    i_ret = DialogSend( p_this, p_new ); 
     316 
     317    if( i_ret != DIALOG_CANCELLED ) 
     318    { 
     319        *ppsz_usersString = p_new->psz_returned[0]? 
     320            strdup( p_new->psz_returned[0] ) : NULL; 
     321    } 
     322    return i_ret; 
     323
     324 
     325/** 
     326 * Hide an interaction dialog 
     327 * 
     328 * \param p_this the parent vlc object 
     329 * \param i_id the id of the item to hide 
    63330 * \return nothing 
    64331 */ 
    65 void intf_InteractionDestroy( interaction_t *p_interaction ) 
     332void __intf_UserHide( vlc_object_t *p_this, int i_id ) 
     333
     334    interaction_t *p_interaction = InteractionGet( p_this ); 
     335    interaction_dialog_t *p_dialog; 
     336 
     337    if( !p_interaction ) return; 
     338 
     339    vlc_object_lock( p_interaction ); 
     340    p_dialog = DialogGetById( p_interaction, i_id ); 
     341 
     342    if( p_dialog ) 
     343        p_dialog->i_status = ANSWERED_DIALOG; 
     344 
     345    vlc_object_unlock( p_interaction ); 
     346    vlc_object_release( p_interaction ); 
     347
     348 
     349/********************************************************************** 
     350 * The following functions are local 
     351 **********************************************************************/ 
     352 
     353/* Get the interaction object. Create it if needed */ 
     354static interaction_t * InteractionGet( vlc_object_t *p_this ) 
     355
     356    interaction_t *p_interaction = 
     357            vlc_object_find( p_this, VLC_OBJECT_INTERACTION, FIND_ANYWHERE ); 
     358 
     359    if( !p_interaction ) 
     360        p_interaction = InteractionInit( p_this->p_libvlc ); 
     361 
     362    return p_interaction; 
     363
     364 
     365/* Create the interaction object in the given playlist object */ 
     366static interaction_t * InteractionInit( libvlc_int_t *p_libvlc ) 
     367
     368    interaction_t *p_interaction = 
     369            vlc_object_create( p_libvlc, VLC_OBJECT_INTERACTION ); 
     370 
     371    if( p_interaction ) 
     372    { 
     373        vlc_object_attach( p_interaction, p_libvlc ); 
     374         
     375        p_interaction->i_dialogs = 0; 
     376        p_interaction->pp_dialogs = NULL; 
     377        p_interaction->p_intf = NULL; 
     378        p_interaction->i_last_id = 0; 
     379 
     380        if( vlc_thread_create( p_interaction, "Interaction control", 
     381                                InteractionLoop, VLC_THREAD_PRIORITY_LOW, 
     382                                VLC_FALSE ) ) 
     383        { 
     384            msg_Err( p_interaction, "Interaction control thread creation failed" 
     385                    ", interaction will not be displayed" ); 
     386            vlc_object_detach( p_interaction ); 
     387            vlc_object_release( p_interaction ); 
     388            p_interaction = NULL; 
     389        } 
     390        else 
     391            vlc_object_yield( p_interaction ); 
     392    } 
     393 
     394    return p_interaction; 
     395
     396 
     397/* Look for an interface suitable for interaction */ 
     398static void InteractionSearchInterface( interaction_t *p_interaction ) 
     399
     400    vlc_list_t  *p_list; 
     401    int          i_index; 
     402 
     403    p_interaction->p_intf = NULL; 
     404 
     405    p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE ); 
     406    if( !p_list ) 
     407    { 
     408        msg_Err( p_interaction, "unable to create module list" ); 
     409        return; 
     410    } 
     411 
     412    for( i_index = 0; i_index < p_list->i_count; i_index ++ ) 
     413    { 
     414        intf_thread_t *p_intf = (intf_thread_t *) 
     415                                        p_list->p_values[i_index].p_object; 
     416        if( p_intf->b_interaction ) 
     417        { 
     418            p_interaction->p_intf = p_intf; 
     419            break; 
     420        } 
     421    } 
     422    vlc_list_release ( p_list ); 
     423
     424 
     425/* Find an interaction dialog by its id */ 
     426static interaction_dialog_t *DialogGetById( interaction_t *p_interaction, 
     427                                            int i_id ) 
    66428{ 
    67429    int i; 
    68     // Remove all dialogs - Interfaces must be able to clean up their data 
     430    for( i = 0 ; i< p_interaction->i_dialogs; i++ ) 
     431    { 
     432        if( p_interaction->pp_dialogs[i]->i_id == i_id ) 
     433            return p_interaction->pp_dialogs[i]; 
     434    } 
     435    return NULL; 
     436
     437 
     438/* Destroy a dialog */ 
     439static void DialogDestroy( interaction_dialog_t *p_dialog ) 
     440
     441    free( p_dialog->psz_title ); 
     442    free( p_dialog->psz_description ); 
     443    free( p_dialog->psz_default_button ); 
     444    free( p_dialog->psz_alternate_button ); 
     445    free( p_dialog->psz_other_button ); 
     446    free( p_dialog ); 
     447
     448 
     449/* Ask for the dialog to be sent to the user. Wait for answer 
     450 * if required */ 
     451static int DialogSend( vlc_object_t *p_this, interaction_dialog_t *p_dialog ) 
     452
     453    interaction_t *p_interaction = InteractionGet( p_this ); 
     454 
     455    /* Get an id, if we don't already have one */ 
     456    if( p_dialog->i_id == 0 ) 
     457        p_dialog->i_id = ++p_interaction->i_last_id; 
     458 
     459    if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT ) return VLC_EGENERIC; 
     460 
     461    if( config_GetInt( p_this, "interact" ) || 
     462        p_dialog->i_flags & DIALOG_BLOCKING_ERROR || 
     463        p_dialog->i_flags & DIALOG_NONBLOCKING_ERROR ) 
     464    { 
     465        vlc_bool_t b_found = VLC_FALSE; 
     466        int i; 
     467        p_dialog->p_interaction = p_interaction; 
     468        p_dialog->p_parent = p_this; 
     469 
     470        /* Check if we have already added this dialog */ 
     471        vlc_object_lock( p_interaction ); 
     472        for( i = 0 ; i< p_interaction->i_dialogs; i++ ) 
     473        { 
     474            if( p_interaction->pp_dialogs[i]->i_id == p_dialog->i_id ) 
     475                b_found = VLC_TRUE; 
     476        } 
     477        /* Add it to the queue, the main loop will send the orders to the 
     478         * interface */ 
     479        if( ! b_found ) 
     480        { 
     481            INSERT_ELEM( p_interaction->pp_dialogs, 
     482                         p_interaction->i_dialogs, 
     483                         p_interaction->i_dialogs, 
     484                         p_dialog ); 
     485        } 
     486        else 
     487            p_dialog->i_status = UPDATED_DIALOG; 
     488 
     489        if( p_dialog->i_type == INTERACT_DIALOG_TWOWAY ) /* Wait for answer */ 
     490        { 
     491            vlc_object_signal_unlocked( p_interaction ); 
     492            while( p_dialog->i_status != ANSWERED_DIALOG && 
     493                   p_dialog->i_status != HIDING_DIALOG && 
     494                   p_dialog->i_status != HIDDEN_DIALOG && 
     495                   !p_dialog->p_parent->b_die ) 
     496            { 
     497                vlc_object_unlock( p_interaction ); 
     498                msleep( 100000 ); 
     499                vlc_object_lock( p_interaction ); 
     500            } 
     501            if( p_dialog->p_parent->b_die ) 
     502            { 
     503                p_dialog->i_return = DIALOG_CANCELLED; 
     504                p_dialog->i_status = ANSWERED_DIALOG; 
     505            } 
     506            p_dialog->i_flags |= DIALOG_GOT_ANSWER; 
     507            vlc_object_signal_unlocked( p_interaction ); 
     508            vlc_object_unlock( p_interaction ); 
     509            vlc_object_release( p_interaction ); 
     510            return p_dialog->i_return; 
     511        } 
     512        else 
     513        { 
     514            /* Pretend we already retrieved the "answer" */ 
     515            p_dialog->i_flags |=  DIALOG_GOT_ANSWER; 
     516            vlc_object_signal_unlocked( p_interaction ); 
     517            vlc_object_unlock( p_interaction ); 
     518            vlc_object_release( p_interaction ); 
     519            return VLC_SUCCESS; 
     520        } 
     521    } 
     522    else 
     523    { 
     524        vlc_object_release( p_interaction ); 
     525        return VLC_EGENERIC; 
     526    } 
     527
     528 
     529static void InteractionLoop( vlc_object_t *p_this ) 
     530
     531    int i; 
     532    interaction_t *p_interaction = (interaction_t*) p_this; 
     533 
     534    while( !p_this->b_die ) 
     535    { 
     536        vlc_object_lock( p_this ); 
     537        if( vlc_object_wait( p_this ) ) 
     538        { 
     539            vlc_object_unlock( p_this ); 
     540            break; 
     541        } 
     542        InteractionManage( p_interaction ); 
     543        vlc_object_unlock( p_this ); 
     544    } 
     545 
     546    /* Remove all dialogs - Interfaces must be able to clean up their data */ 
    69547    for( i = p_interaction->i_dialogs -1 ; i >= 0; i-- ) 
    70548    { 
     
    73551        REMOVE_ELEM( p_interaction->pp_dialogs, p_interaction->i_dialogs, i ); 
    74552    } 
    75     vlc_object_release( p_interaction ); 
     553 
     554    vlc_object_detach( p_this ); 
     555    vlc_object_release( p_this ); 
    76556} 
    77557 
    78558/** 
    79559 * The main interaction processing loop 
    80  * This function is called from the playlist loop 
    81  * 
    82  * \param p_playlist the parent playlist 
     560 * 
     561 * \param p_interaction the interaction object 
    83562 * \return nothing 
    84563 */ 
    85 void intf_InteractionManage( playlist_t *p_playlist ) 
     564 
     565static void InteractionManage( interaction_t *p_interaction ) 
    86566{ 
    87567    vlc_value_t val; 
    88568    int i_index; 
    89     interaction_t *p_interaction = p_playlist->p_interaction; 
    90  
    91     // Nothing to do 
     569 
     570    /* Nothing to do */ 
    92571    if( p_interaction->i_dialogs == 0 ) return; 
    93  
    94     vlc_mutex_lock( &p_interaction->object_lock ); 
    95572 
    96573    InteractionSearchInterface( p_interaction ); 
    97574    if( !p_interaction->p_intf ) 
    98575    { 
    99         // We mark all dialogs as answered with their "default" answer 
     576        /* We mark all dialogs as answered with their "default" answer */ 
    100577        for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ ) 
    101578        { 
    102579            interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index]; 
    103             p_dialog->i_return = DIALOG_DEFAULT; // Give default answer 
    104  
    105             // Pretend we have hidden and destroyed it 
     580            p_dialog->i_return = DIALOG_DEFAULT; /* Give default answer */ 
     581 
     582            /* Pretend we have hidden and destroyed it */ 
    106583            if( p_dialog->i_status == HIDDEN_DIALOG ) 
    107584                p_dialog->i_status = DESTROYED_DIALOG; 
     
    119596        { 
    120597        case ANSWERED_DIALOG: 
    121             // Ask interface to hide it 
     598            /* Ask interface to hide it */ 
    122599            p_dialog->i_action = INTERACT_HIDE; 
    123600            val.p_address = p_dialog; 
     
    141618            break; 
    142619        case DESTROYED_DIALOG: 
    143             // Interface has now destroyed it, remove it 
     620            /* Interface has now destroyed it, remove it */ 
    144621            REMOVE_ELEM( p_interaction->pp_dialogs, p_interaction->i_dialogs, 
    145622                         i_index); 
     
    148625            break; 
    149626        case NEW_DIALOG: 
    150             // This is truly a new dialog, send it. 
     627            /* This is truly a new dialog, send it. */ 
     628 
    151629            p_dialog->i_action = INTERACT_NEW; 
    152630            val.p_address = p_dialog; 
     
    159637 
    160638    if( p_interaction->p_intf ) 
    161     { 
    162639        vlc_object_release( p_interaction->p_intf ); 
    163     } 
    164  
    165     vlc_mutex_unlock( &p_playlist->p_interaction->object_lock ); 
    166 
    167  
    168 #define DIALOG_INIT( type ) \ 
    169         DECMALLOC_ERR( p_new, interaction_dialog_t );                     \ 
    170         memset( p_new, 0, sizeof( interaction_dialog_t ) );               \ 
    171         p_new->b_cancelled = VLC_FALSE;                                   \ 
    172         p_new->i_status = NEW_DIALOG;                                     \ 
    173         p_new->i_flags = 0; \ 
    174         p_new->i_type = INTERACT_DIALOG_##type;                           \ 
    175         p_new->psz_returned[0] = NULL;                                    \ 
    176         p_new->psz_returned[1] = NULL; 
    177  
    178 #define FORMAT_DESC \ 
    179         va_start( args, psz_format ); \ 
    180         vasprintf( &p_new->psz_description, psz_format, args ); \ 
    181         va_end( args ); 
    182  
    183 /** 
    184  * Send an error message, both in a blocking and non-blocking way 
    185  * 
    186  * \param p_this     Parent vlc_object 
    187  * \param b_blocking Is this dialog blocking or not? 
    188  * \param psz_title  Title for the dialog 
    189  * \param psz_format The message to display 
    190  * \return           VLC_SUCCESS or VLC_EGENERIC 
    191  */ 
    192 int __intf_UserFatal( vlc_object_t *p_this, vlc_bool_t b_blocking, 
    193                        const char *psz_title, 
    194                        const char *psz_format, ... ) 
    195 
    196     va_list args; 
    197     DIALOG_INIT( ONEWAY ); 
    198  
    199     p_new->psz_title = strdup( psz_title ); 
    200     FORMAT_DESC; 
    201  
    202     if( b_blocking ) 
    203         p_new->i_flags = DIALOG_BLOCKING_ERROR; 
    204     else 
    205         p_new->i_flags = DIALOG_NONBLOCKING_ERROR; 
    206  
    207     return DialogSend( p_this, p_new ); 
    208 
    209  
    210 /** 
    211  * Helper function to send a warning, which is always shown non-blocking 
    212  * 
    213  * \param p_this     Parent vlc_object 
    214  * \param psz_title  Title for the dialog 
    215  * \param psz_format The message to display 
    216  * \return           VLC_SUCCESS or VLC_EGENERIC 
    217  */ 
    218 int __intf_UserWarn( vlc_object_t *p_this, 
    219                      const char *psz_title, 
    220                      const char *psz_format, ... ) 
    221 
    222     va_list args; 
    223     DIALOG_INIT( ONEWAY ); 
    224  
    225     p_new->psz_title = strdup( psz_title ); 
    226     FORMAT_DESC 
    227  
    228     p_new->i_flags = DIALOG_WARNING; 
    229  
    230     return DialogSend( p_this, p_new ); 
    231 
    232  
    233 /** 
    234  * Helper function to ask a yes-no-cancel question 
    235  * 
    236  * \param p_this           Parent vlc_object 
    237  * \param psz_title        Title for the dialog 
    238  * \param psz_description  A description 
    239  * \param psz_default      caption for the default button 
    240  * \param psz_alternate    caption for the alternate button 
    241  * \param psz_other        caption for the optional 3rd button (== cancel) 
    242  * \return                 Clicked button code 
    243  */ 
    244 int __intf_UserYesNo( vlc_object_t *p_this, 
    245                       const char *psz_title, 
    246                       const char *psz_description, 
    247                       const char *psz_default, 
    248                       const char *psz_alternate, 
    249                       const char *psz_other ) 
    250 
    251     DIALOG_INIT( TWOWAY ); 
    252  
    253     p_new->psz_title = strdup( psz_title ); 
    254     p_new->psz_description = strdup( psz_description ); 
    255     p_new->i_flags = DIALOG_YES_NO_CANCEL; 
    256     p_new->psz_default_button = strdup( psz_default ); 
    257     p_new->psz_alternate_button = strdup( psz_alternate ); 
    258     if( psz_other ) 
    259         p_new->psz_other_button = strdup( psz_other ); 
    260  
    261     return DialogSend( p_this, p_new ); 
    262 
    263  
    264 /** 
    265  * Helper function to create a dialogue showing a progress-bar with some info 
    266  * 
    267  * \param p_this           Parent vlc_object 
    268  * \param psz_title        Title for the dialog (NULL implies main intf ) 
    269  * \param psz_status       Current status 
    270  * \param f_position       Current position (0.0->100.0) 
    271  * \param i_timeToGo       Time (in sec) to go until process is finished 
    272  * \return                 Dialog id, to give to UserProgressUpdate 
    273  */ 
    274 int __intf_Progress( vlc_object_t *p_this, const char *psz_title, 
    275                      const char *psz_status, float f_pos, int i_time ) 
    276 
    277     DIALOG_INIT( ONEWAY ); 
    278     p_new->psz_description = strdup( psz_status ); 
    279     p_new->val.f_float = f_pos; 
    280     p_new->i_timeToGo = i_time; 
    281     p_new->psz_alternate_button = strdup( _( "Cancel" ) ); 
    282  
    283     if( psz_title ) 
    284     { 
    285         p_new->psz_title = strdup( psz_title ); 
    286         p_new->i_flags = DIALOG_USER_PROGRESS; 
    287     } 
    288     else 
    289         p_new->i_flags = DIALOG_INTF_PROGRESS; 
    290  
    291     DialogSend( p_this, p_new ); 
    292     return p_new->i_id; 
    293 
    294  
    295 /** 
    296  * Update a progress bar in a dialogue 
    297  * 
    298  * \param p_this           Parent vlc_object 
    299  * \param i_id             Identifier of the dialog 
    300  * \param psz_status       New status 
    301  * \param f_position       New position (0.0->100.0) 
    302  * \param i_timeToGo       Time (in sec) to go until process is finished 
    303  * \return                 nothing 
    304  */ 
    305 void __intf_ProgressUpdate( vlc_object_t *p_this, int i_id, 
    306                             const char *psz_status, float f_pos, int i_time ) 
    307 
    308     interaction_t *p_interaction = InteractionGet( p_this ); 
    309     interaction_dialog_t *p_dialog; 
    310  
    311     if( !p_interaction ) return; 
    312  
    313     vlc_mutex_lock( &p_interaction->object_lock ); 
    314     p_dialog  =  DialogGetById( p_interaction, i_id ); 
    315  
    316     if( !p_dialog ) 
    317     { 
    318         vlc_mutex_unlock( &p_interaction->object_lock ) ; 
    319         return; 
    320     } 
    321  
    322     free( p_dialog->psz_description ); 
    323     p_dialog->psz_description = strdup( psz_status ); 
    324  
    325     p_dialog->val.f_float = f_pos; 
    326     p_dialog->i_timeToGo = i_time; 
    327  
    328     p_dialog->i_status = UPDATED_DIALOG; 
    329     vlc_mutex_unlock( &p_interaction->object_lock) ; 
    330  
    331     playlist_Signal( pl_Get( p_this ) ); 
    332 
    333  
    334 /** 
    335  * Helper function to communicate dialogue cancellations between the 
    336  * interface module and the caller 
    337  * 
    338  * \param p_this           Parent vlc_object 
    339  * \param i_id             Identifier of the dialogue 
    340  * \return                 Either true or false 
    341  */ 
    342 vlc_bool_t __intf_UserProgressIsCancelled( vlc_object_t *p_this, int i_id ) 
    343 
    344     interaction_t *p_interaction = InteractionGet( p_this ); 
    345     interaction_dialog_t *p_dialog; 
    346     vlc_bool_t b_cancel; 
    347  
    348     if( !p_interaction ) return VLC_TRUE; 
    349  
    350     vlc_mutex_lock( &p_interaction->object_lock ); 
    351     p_dialog  =  DialogGetById( p_interaction, i_id ); 
    352     if( !p_dialog ) 
    353     { 
    354         vlc_mutex_unlock( &p_interaction->object_lock ) ; 
    355         return VLC_TRUE; 
    356     } 
    357  
    358     b_cancel = p_dialog->b_cancelled; 
    359     vlc_mutex_unlock( &p_interaction->object_lock ); 
    360     return b_cancel; 
    361 
    362  
    363 /** 
    364  * Helper function to make a login/password dialogue 
    365  * 
    366  * \param p_this           Parent vlc_object 
    367  * \param psz_title        Title for the dialog 
    368  * \param psz_description  A description 
    369  * \param ppsz_login       Returned login 
    370  * \param ppsz_password    Returned password 
    371  * \return                 Clicked button code 
    372  */ 
    373 int __intf_UserLoginPassword( vlc_object_t *p_this, 
    374                               const char *psz_title, 
    375                               const char *psz_description, 
    376                               char **ppsz_login, 
    377                               char **ppsz_password ) 
    378 
    379     int i_ret; 
    380     DIALOG_INIT( TWOWAY ); 
    381     p_new->i_type = INTERACT_DIALOG_TWOWAY; 
    382     p_new->psz_title = strdup( psz_title ); 
    383     p_new->psz_description = strdup( psz_description ); 
    384     p_new->psz_default_button = strdup( _("Ok" ) ); 
    385     p_new->psz_alternate_button = strdup( _("Cancel" ) ); 
    386  
    387     p_new->i_flags = DIALOG_LOGIN_PW_OK_CANCEL; 
    388  
    389     i_ret = DialogSend( p_this, p_new ); 
    390  
    391     if( i_ret != DIALOG_CANCELLED && i_ret != VLC_EGENERIC ) 
    392     { 
    393         *ppsz_login = p_new->psz_returned[0]? 
    394                                 strdup( p_new->psz_returned[0] ) : NULL; 
    395         *ppsz_password = p_new->psz_returned[1]? 
    396                                 strdup( p_new->psz_returned[1] ) : NULL; 
    397     } 
    398     return i_ret; 
    399 
    400  
    401 /** 
    402  * Helper function to make a dialogue asking the user for !password string 
    403  * 
    404  * \param p_this           Parent vlc_object 
    405  * \param psz_title        Title for the dialog 
    406  * \param psz_description  A description 
    407  * \param ppsz_usersString Returned login 
    408  * \return                 Clicked button code 
    409  */ 
    410 int __intf_UserStringInput( vlc_object_t *p_this, 
    411                               const char *psz_title, 
    412                               const char *psz_description, 
    413                               char **ppsz_usersString ) 
    414 
    415     int i_ret; 
    416     DIALOG_INIT( TWOWAY ); 
    417     p_new->i_type = INTERACT_DIALOG_TWOWAY; 
    418     p_new->psz_title = strdup( psz_title ); 
    419     p_new->psz_description = strdup( psz_description ); 
    420  
    421     p_new->i_flags = DIALOG_PSZ_INPUT_OK_CANCEL; 
    422  
    423     i_ret = DialogSend( p_this, p_new ); 
    424  
    425     if( i_ret != DIALOG_CANCELLED ) 
    426     { 
    427         *ppsz_usersString = p_new->psz_returned[0]? 
    428                                     strdup( p_new->psz_returned[0] ) : NULL; 
    429     } 
    430     return i_ret; 
    431 
    432  
    433 /** 
    434  * Hide an interaction dialog 
    435  * 
    436  * \param p_this the parent vlc object 
    437  * \param i_id the id of the item to hide 
    438  * \return nothing 
    439  */ 
    440 void __intf_UserHide( vlc_object_t *p_this, int i_id ) 
    441 
    442     interaction_t *p_interaction = InteractionGet( p_this ); 
    443     interaction_dialog_t *p_dialog; 
    444  
    445     if( !p_interaction ) return; 
    446  
    447     vlc_mutex_lock( &p_interaction->object_lock ); 
    448     p_dialog = DialogGetById( p_interaction, i_id ); 
    449  
    450     if( !p_dialog ) 
    451     { 
    452        vlc_mutex_unlock( &p_interaction->object_lock ); 
    453        return; 
    454     } 
    455  
    456     p_dialog->i_status = ANSWERED_DIALOG; 
    457     vlc_mutex_unlock( &p_interaction->object_lock ); 
    458 
    459  
    460 /********************************************************************** 
    461  * The following functions are local 
    462  **********************************************************************/ 
    463  
    464 /* Get the interaction object. Create it if needed */ 
    465 static interaction_t * InteractionGet( vlc_object_t *p_this ) 
    466 
    467     interaction_t *p_interaction; 
    468     playlist_t *p_playlist = pl_Yield( p_this ); 
    469  
    470     PL_LOCK; 
    471     if( p_playlist->p_interaction == NULL ) 
    472        InteractionInit( p_playlist ); 
    473  
    474     p_interaction = p_playlist->p_interaction; 
    475     PL_UNLOCK; 
    476  
    477     pl_Release( p_this ); 
    478     return p_interaction; 
    479 
    480  
    481 /* Create the interaction object in the given playlist object */ 
    482 static void InteractionInit( playlist_t *p_playlist ) 
    483 
    484     interaction_t *p_interaction = vlc_object_create( VLC_OBJECT( p_playlist ), 
    485                                                       sizeof( interaction_t ) ); 
    486     if( !p_interaction ) 
    487     { 
    488         msg_Err( p_playlist,"out of memory" ); 
    489         return; 
    490     } 
    491  
    492     p_interaction->psz_object_name = "interaction"; 
    493     p_interaction->i_dialogs = 0; 
    494     p_interaction->pp_dialogs = NULL; 
    495     p_interaction->p_intf = NULL; 
    496     p_interaction->i_last_id = 0; 
    497  
    498     vlc_mutex_init( p_interaction , &p_interaction->object_lock ); 
    499     p_playlist->p_interaction  = p_interaction; 
    500 
    501  
    502 /* Look for an interface suitable for interaction */ 
    503 static void InteractionSearchInterface( interaction_t *p_interaction ) 
    504 
    505     vlc_list_t  *p_list; 
    506     int          i_index; 
    507  
    508     p_interaction->p_intf = NULL; 
    509  
    510     p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE ); 
    511     if( !p_list ) 
    512     { 
    513         msg_Err( p_interaction, "unable to create module list" ); 
    514         return; 
    515     } 
    516  
    517     for( i_index = 0; i_index < p_list->i_count; i_index ++ ) 
    518     { 
    519         intf_thread_t *p_intf = (intf_thread_t *) 
    520                                         p_list->p_values[i_index].p_object; 
    521         if( p_intf->b_interaction ) 
    522         { 
    523             p_interaction->p_intf = p_intf; 
    524             break; 
    525         } 
    526     } 
    527     vlc_list_release ( p_list ); 
    528 
    529  
    530 /* Find an interaction dialog by its id */ 
    531 static interaction_dialog_t *DialogGetById( interaction_t *p_interaction, 
    532                                             int i_id ) 
    533 
    534     int i; 
    535     for( i = 0 ; i< p_interaction->i_dialogs; i++ ) 
    536     { 
    537         if( p_interaction->pp_dialogs[i]->i_id == i_id ) 
    538             return p_interaction->pp_dialogs[i]; 
    539     } 
    540     return NULL; 
    541 
    542  
    543 /* Destroy a dialog */ 
    544 static void DialogDestroy( interaction_dialog_t *p_dialog ) 
    545 
    546     free( p_dialog->psz_title ); 
    547     free( p_dialog->psz_description ); 
    548     free( p_dialog->psz_default_button ); 
    549     free( p_dialog->psz_alternate_button ); 
    550     free( p_dialog->psz_other_button ); 
    551     free( p_dialog ); 
    552 
    553  
    554 /* Ask for the dialog to be sent to the user. Wait for answer 
    555  * if required */ 
    556 static int DialogSend( vlc_object_t *p_this, interaction_dialog_t *p_dialog ) 
    557 
    558     interaction_t *p_interaction = InteractionGet( p_this ); 
    559  
    560     /* Get an id, if we don't already have one */ 
    561     if( p_dialog->i_id == 0 ) 
    562         p_dialog->i_id = ++p_interaction->i_last_id; 
    563  
    564     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT ) return VLC_EGENERIC; 
    565  
    566     if( config_GetInt( p_this, "interact" ) || 
    567         p_dialog->i_flags & DIALOG_BLOCKING_ERROR || 
    568         p_dialog->i_flags & DIALOG_NONBLOCKING_ERROR ) 
    569     {