From: Clément Stenac Date: Sun, 11 Dec 2005 16:06:19 +0000 (+0000) Subject: * Handle dialogs needing answer X-Git-Tag: 0.9.0-test0~12949 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=15354b0406c9222fd39dcee94f9d7239d65d5f39;p=vlc * Handle dialogs needing answer * Handle interfaces not providing interaction correctly * Add a new helper to request authentication * Add return codes --- diff --git a/include/vlc_interaction.h b/include/vlc_interaction.h index e289101686..b76cf57925 100644 --- a/include/vlc_interaction.h +++ b/include/vlc_interaction.h @@ -39,7 +39,7 @@ enum { WIDGET_TEXT, //< Text display WIDGET_PROGRESS, //< A progress bar - WIDGET_INPUT //< Input (backed up by a variable) + WIDGET_INPUT_TEXT //< Input (backed up by a variable) }; /** @@ -52,16 +52,39 @@ struct interaction_dialog_t char *psz_title; //< Title char *psz_description; //< Descriptor string - /* For dialogs */ int i_widgets; //< Nu,ber of dialog widgets user_widget_t **pp_widgets; //< Dialog widgets - vlc_bool_t b_reusable; //< Do we have to reuse this ? - void * p_private; //< Private interface data - int i_status; //< Dialog status; + int i_status; //< Dialog status; int i_action; //< Action to perform; + int i_flags; //< Misc flags + int i_return; //< Return status + + interaction_t *p_interaction; //< Parent interaction object + vlc_object_t *p_parent; //< The vlc object that asked + //for interaction +}; + +/** + * Possible flags . Reusable and button types + */ +#define DIALOG_REUSABLE 0x01 +#define DIALOG_OK_CANCEL 0x02 +#define DIALOG_YES_NO 0x04 +#define DIALOG_YES_NO_CANCEL 0x04 +#define DIALOG_GOT_ANSWER 0x08 + +/** + * Possible return codes + */ +enum +{ + DIALOG_DEFAULT, + DIALOG_OK_YES, + DIALOG_NO, + DIALOG_CANCELLED }; /** @@ -69,12 +92,13 @@ struct interaction_dialog_t */ enum { - NEW_DIALOG, - SENT_DIALOG, - UPDATED_DIALOG, - ANSWERED_DIALOG, - HIDING_DIALOG, - HIDDEN_DIALOG, + NEW_DIALOG, //< Just created + SENT_DIALOG, //< Sent to interface + UPDATED_DIALOG, //< Update to send + ANSWERED_DIALOG, //< Got "answer" + HIDING_DIALOG, //< Hiding requested + HIDDEN_DIALOG, //< Now hidden. Requesting destruction + DESTROYED_DIALOG, //< Interface has destroyed it }; /** @@ -82,11 +106,9 @@ enum */ enum { - INTERACT_PROGRESS, //< Progress bar - INTERACT_WARNING, //< Warning message ("codec not supported") - INTERACT_FATAL, //< Fatal message ("File not found") - INTERACT_FATAL_LIST, //< List of fatal messages ("File not found") - INTERACT_ASK, //< Full-featured dialog box (password) + INTERACT_PROGRESS, //< Progress bar (in the main interface ?) + INTERACT_DIALOG_ONEWAY, //< Dialog box without feedback + INTERACT_DIALOG_TWOWAY, //< Dialog box with feedback }; /** @@ -95,9 +117,7 @@ enum enum { DIALOG_FIRST, - DIALOG_NOACCESS, - DIALOG_NOCODEC, - DIALOG_NOAUDIO, + DIALOG_ERRORS, DIALOG_LAST_PREDEFINED, }; @@ -124,7 +144,8 @@ enum { INTERACT_NEW, INTERACT_UPDATE, - INTERACT_HIDE + INTERACT_HIDE, + INTERACT_DESTROY }; /*************************************************************************** @@ -134,8 +155,10 @@ enum #define intf_Interact( a,b ) __intf_Interact( VLC_OBJECT(a), b ) VLC_EXPORT( int,__intf_Interact,( vlc_object_t *,interaction_dialog_t * ) ); -#define intf_UserFatal( a,b, c, d, e... ) __intf_UserFatal( a,b,c,d, ## e ) -VLC_EXPORT( void, __intf_UserFatal,( vlc_object_t*, int, const char*, const char*, ...) ); +#define intf_UserFatal( a, c, d, e... ) __intf_UserFatal( a,c,d, ## e ) +VLC_EXPORT( void, __intf_UserFatal,( vlc_object_t*, const char*, const char*, ...) ); +#define intf_UserLoginPassword( a, b, c, d, e... ) __intf_UserLoginPassword( a,b,c,d,e) +VLC_EXPORT( int, __intf_UserLoginPassword,( vlc_object_t*, const char*, const char*, char **, char **) ); VLC_EXPORT( void, intf_InteractionManage,( playlist_t *) ); VLC_EXPORT( void, intf_InteractionDestroy,( interaction_t *) ); diff --git a/include/vlc_interface.h b/include/vlc_interface.h index b05f1d78b1..701cc1b8a7 100644 --- a/include/vlc_interface.h +++ b/include/vlc_interface.h @@ -92,6 +92,7 @@ struct intf_thread_t *****************************************************************************/ struct intf_dialog_args_t { + intf_thread_t *p_intf; char *psz_title; char **psz_results; @@ -104,6 +105,9 @@ struct intf_dialog_args_t char *psz_extensions; vlc_bool_t b_save; vlc_bool_t b_multiple; + + /* Specific to INTF_DIALOG_INTERACTION */ + interaction_dialog_t *p_dialog; }; /***************************************************************************** @@ -160,6 +164,7 @@ VLC_EXPORT( void, intf_Destroy, ( intf_thread_t * ) ); #define INTF_DIALOG_POPUPMENU 20 #define INTF_DIALOG_FILE_GENERIC 30 +#define INTF_DIALOG_INTERACTION 50 #define INTF_DIALOG_UPDATEVLC 90 #define INTF_DIALOG_VLM 91 diff --git a/include/vlc_symbols.h b/include/vlc_symbols.h index 6f1d28ec79..1a1a19a606 100644 --- a/include/vlc_symbols.h +++ b/include/vlc_symbols.h @@ -145,6 +145,7 @@ int playlist_Export (playlist_t *, const char *, const char *); demux_t * __demux2_New (vlc_object_t *p_obj, char *psz_access, char *psz_demux, char *psz_path, stream_t *s, es_out_t *out, vlc_bool_t); int __vlc_threads_end (vlc_object_t *); int sout_AccessOutRead (sout_access_out_t *, block_t *); +int __intf_UserLoginPassword (vlc_object_t*, const char*, const char*, char **, char **); int demux2_vaControlHelper (stream_t *, int64_t i_start, int64_t i_end, int i_bitrate, int i_align, int i_query, va_list args); int httpd_UrlCatch (httpd_url_t *, int i_msg, httpd_callback_t, httpd_callback_sys_t *); void __vlc_object_yield (vlc_object_t *); @@ -297,7 +298,7 @@ subpicture_t * spu_CreateSubpicture (spu_t *); void httpd_MsgAdd (httpd_message_t *, char *psz_name, char *psz_value, ...); int vout_vaControlDefault (vout_thread_t *, int, va_list); int playlist_NodeEmpty (playlist_t *, playlist_item_t *, vlc_bool_t); -void __intf_UserFatal (vlc_object_t*, int, const char*, const char*, ...); +void __intf_UserFatal (vlc_object_t*, const char*, const char*, ...); spu_t * __spu_Create (vlc_object_t *); int playlist_NodeRemoveItem (playlist_t *,playlist_item_t*,playlist_item_t *); int __net_Accept (vlc_object_t *, int *, mtime_t); @@ -858,7 +859,8 @@ struct module_symbols_t int (*__intf_Interact_inner) (vlc_object_t *,interaction_dialog_t *); void (*intf_InteractionManage_inner) (playlist_t *); void (*intf_InteractionDestroy_inner) (interaction_t *); - void (*__intf_UserFatal_inner) (vlc_object_t*, int, const char*, const char*, ...); + void (*__intf_UserFatal_inner) (vlc_object_t*, const char*, const char*, ...); + int (*__intf_UserLoginPassword_inner) (vlc_object_t*, const char*, const char*, char **, char **); }; # if defined (__PLUGIN__) # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner @@ -1274,6 +1276,7 @@ struct module_symbols_t # define intf_InteractionManage (p_symbols)->intf_InteractionManage_inner # define intf_InteractionDestroy (p_symbols)->intf_InteractionDestroy_inner # define __intf_UserFatal (p_symbols)->__intf_UserFatal_inner +# define __intf_UserLoginPassword (p_symbols)->__intf_UserLoginPassword_inner # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__) /****************************************************************** * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. @@ -1692,6 +1695,7 @@ struct module_symbols_t ((p_symbols)->intf_InteractionManage_inner) = intf_InteractionManage; \ ((p_symbols)->intf_InteractionDestroy_inner) = intf_InteractionDestroy; \ ((p_symbols)->__intf_UserFatal_inner) = __intf_UserFatal; \ + ((p_symbols)->__intf_UserLoginPassword_inner) = __intf_UserLoginPassword; \ (p_symbols)->net_ConvertIPv4_deprecated = NULL; \ # endif /* __PLUGIN__ */ diff --git a/src/input/input.c b/src/input/input.c index 5ab59b5085..69c4f8c7d8 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -2095,9 +2095,8 @@ static int InputSourceInit( input_thread_t *p_input, if( in->p_access == NULL ) { msg_Err( p_input, "no suitable access module for `%s'", psz_mrl ); - intf_UserFatal( VLC_OBJECT( p_input), DIALOG_NOACCESS, - "Error opening stream", - "Unable to open '%s'", psz_mrl ); + intf_UserFatal( VLC_OBJECT( p_input), + _("Errors"),"Unable to open '%s'", psz_mrl ); goto error; } @@ -2167,6 +2166,8 @@ static int InputSourceInit( input_thread_t *p_input, { msg_Err( p_input, "no suitable demux module for `%s/%s://%s'", psz_access, psz_demux, psz_path ); + intf_UserFatal( VLC_OBJECT( p_input), _("Errors"), + "Unrecognized format for '%s'", psz_mrl ); goto error; } diff --git a/src/interface/interaction.c b/src/interface/interaction.c index e276e2bf16..2cfcb3e987 100644 --- a/src/interface/interaction.c +++ b/src/interface/interaction.c @@ -63,7 +63,6 @@ static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* , int ); int __intf_Interact( vlc_object_t *p_this, interaction_dialog_t * p_dialog ) { - interaction_t *p_interaction = intf_InteractionGet( p_this ); /* Get an id, if we don't already have one */ @@ -72,12 +71,16 @@ int __intf_Interact( vlc_object_t *p_this, interaction_dialog_t * p_dialog->i_id = ++p_interaction->i_last_id; } - if( p_dialog->i_type == INTERACT_ASK ) + p_dialog->p_interaction = p_interaction; + p_dialog->p_parent = p_this; + + if( p_dialog->i_type == INTERACT_DIALOG_TWOWAY ) { return intf_WaitAnswer( p_interaction, p_dialog ); } else { + p_dialog->i_flags |= DIALOG_GOT_ANSWER; return intf_Send( p_interaction, p_dialog ); } } @@ -114,59 +117,78 @@ void intf_InteractionManage( playlist_t *p_playlist ) if( !p_interaction->p_intf ) { - vlc_mutex_unlock( &p_interaction->object_lock ); - - /// \todo Remove all dialogs as we can't display them - return; + // We mark all dialogs as answered with their "default" answer + for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ ) + { + interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index]; + p_dialog->i_return = DIALOG_DEFAULT; + if( p_dialog->i_flags & DIALOG_OK_CANCEL ) + p_dialog->i_return = DIALOG_CANCELLED; + if( p_dialog->i_flags & DIALOG_YES_NO_CANCEL ) + p_dialog->i_return = DIALOG_CANCELLED; + p_dialog->i_status = ANSWERED_DIALOG; + } + } + else + { + vlc_object_yield( p_interaction->p_intf ); } - - vlc_object_yield( p_interaction->p_intf ); for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ ) { interaction_dialog_t *p_dialog = p_interaction->pp_dialogs[i_index]; - switch( p_dialog->i_status ) { case ANSWERED_DIALOG: - /// \todo Signal we have an answer - // - If have answer, signal what is waiting - // (vlc_cond ? dangerous in case of pb ?) - // Ask interface to hide it msg_Dbg( p_interaction, "Hiding dialog %i", p_dialog->i_id ); p_dialog->i_action = INTERACT_HIDE; val.p_address = p_dialog; - var_Set( p_interaction->p_intf, "interaction", val ); + if( p_interaction->p_intf ) + var_Set( p_interaction->p_intf, "interaction", val ); p_dialog->i_status = HIDING_DIALOG; break; case UPDATED_DIALOG: p_dialog->i_action = INTERACT_UPDATE; val.p_address = p_dialog; - var_Set( p_interaction->p_intf, "interaction", val ); + if( p_interaction->p_intf ) + var_Set( p_interaction->p_intf, "interaction", val ); p_dialog->i_status = SENT_DIALOG; msg_Dbg( p_interaction, "Updating dialog %i, %i widgets", p_dialog->i_id, p_dialog->i_widgets ); break; case HIDDEN_DIALOG: - if( !p_dialog->b_reusable ) + if( !(p_dialog->i_flags & DIALOG_GOT_ANSWER) ) break; + if( !(p_dialog->i_flags & DIALOG_REUSABLE) ) { - /// \todo Destroy the dialog + msg_Dbg( p_interaction, "Destroying dialog %i", + p_dialog->i_id ); + p_dialog->i_action = INTERACT_DESTROY; + val.p_address = p_dialog; + if( p_interaction->p_intf ) + var_Set( p_interaction->p_intf, "interaction", val ); } break; + case DESTROYED_DIALOG: + // Interface has now destroyed it, remove it + /// \todo Remove it from the list + /// \todo Free data fields + free( p_dialog ); case NEW_DIALOG: // This is truly a new dialog, send it. p_dialog->i_action = INTERACT_NEW; val.p_address = p_dialog; - var_Set( p_interaction->p_intf, "interaction", val ); - msg_Dbg( p_interaction, "Creating dialog %i to interface %i, %i widgets", - p_dialog->i_id, p_interaction->p_intf->i_object_id, p_dialog->i_widgets ); + if( p_interaction->p_intf ) + var_Set( p_interaction->p_intf, "interaction", val ); p_dialog->i_status = SENT_DIALOG; break; } } - vlc_object_release( p_interaction->p_intf ); + if( p_interaction->p_intf ) + { + vlc_object_release( p_interaction->p_intf ); + } vlc_mutex_unlock( &p_playlist->p_interaction->object_lock ); } @@ -187,19 +209,20 @@ void intf_InteractionManage( playlist_t *p_playlist ) if( new->psz_title ) free( new->psz_title ); \ if( new->psz_description ) free( new->psz_description ); -/** Helper function to send a fatal message +/** Helper function to send an error message * \param p_this Parent vlc_object * \param i_id A predefined ID, 0 if not applicable * \param psz_title Title for the dialog * \param psz_format The message to display * */ -void __intf_UserFatal( vlc_object_t *p_this, int i_id, +void __intf_UserFatal( vlc_object_t *p_this, const char *psz_title, const char *psz_format, ... ) { va_list args; interaction_dialog_t *p_new = NULL; user_widget_t *p_widget = NULL; + int i_id = DIALOG_ERRORS; if( i_id > 0 ) { @@ -215,7 +238,9 @@ void __intf_UserFatal( vlc_object_t *p_this, int i_id, p_new->i_status = UPDATED_DIALOG; } - p_new->i_type = INTERACT_FATAL; + p_new->i_flags |= DIALOG_REUSABLE; + + p_new->i_type = INTERACT_DIALOG_ONEWAY; p_new->psz_title = strdup( psz_title ); p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) ); @@ -234,22 +259,63 @@ void __intf_UserFatal( vlc_object_t *p_this, int i_id, intf_Interact( p_this, p_new ); } -#if 0 -/** Helper function to build a progress bar - * \param p_this Parent vlc object +/** Helper function to make a login/password box + * \param p_this Parent vlc_object + * \param psz_title Title for the dialog + * \param psz_description A description + * \param ppsz_login Returned login + * \param ppsz_password Returned password + * \return 1 if user clicked Cancel, 0 if OK */ -interaction_dialog_t *__intf_ProgressBuild( vlc_object_t *p_this, - const char *psz_text ) +int __intf_UserLoginPassword( vlc_object_t *p_this, + const char *psz_title, + const char *psz_description, + char **ppsz_login, + char **ppsz_password ) { - interaction_dialog_t *p_new = (interaction_dialog_t *)malloc( - sizeof( interaction_dialog_t ) ); + int i_ret; + interaction_dialog_t *p_new = NULL; + user_widget_t *p_widget = NULL; + INTERACT_INIT( p_new ); - return p_new; -} -#endif + p_new->i_type = INTERACT_DIALOG_TWOWAY; + p_new->psz_title = strdup( psz_title ); + + /* Text */ + p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) ); + p_widget->i_type = WIDGET_TEXT; + p_widget->psz_text = strdup( psz_description ); + INSERT_ELEM ( p_new->pp_widgets, p_new->i_widgets, + p_new->i_widgets, p_widget ); + + /* Login */ + p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) ); + p_widget->i_type = WIDGET_INPUT_TEXT; + p_widget->psz_text = strdup( _("Login") ); + p_widget->val.psz_string = NULL; + INSERT_ELEM ( p_new->pp_widgets, p_new->i_widgets, + p_new->i_widgets, p_widget ); + /* Password */ + p_widget = (user_widget_t* )malloc( sizeof( user_widget_t ) ); + p_widget->i_type = WIDGET_INPUT_TEXT; + p_widget->psz_text = strdup( _("Password") ); + p_widget->val.psz_string = NULL; + INSERT_ELEM ( p_new->pp_widgets, p_new->i_widgets, + p_new->i_widgets, p_widget ); + p_new->i_flags = DIALOG_OK_CANCEL; + + i_ret = intf_Interact( p_this, p_new ); + + if( i_ret == DIALOG_OK_YES ) + { + *ppsz_login = strdup( p_new->pp_widgets[1]->val.psz_string ); + *ppsz_password = strdup( p_new->pp_widgets[2]->val.psz_string ); + } + return i_ret; +} /********************************************************************** * The following functions are local @@ -337,20 +403,67 @@ static void intf_InteractionSearchInterface( interaction_t *p_interaction ) /* Add a dialog to the queue and wait for answer */ static int intf_WaitAnswer( interaction_t *p_interact, interaction_dialog_t *p_dialog ) { - // TODO: Add to queue, wait for answer - return VLC_SUCCESS; + int i; + vlc_bool_t b_found = VLC_FALSE; + vlc_mutex_lock( &p_interact->object_lock ); + for( i = 0 ; i< p_interact->i_dialogs; i++ ) + { + if( p_interact->pp_dialogs[i]->i_id == p_dialog->i_id ) + { + b_found = VLC_TRUE; + } + } + if( ! b_found ) + { + INSERT_ELEM( p_interact->pp_dialogs, + p_interact->i_dialogs, + p_interact->i_dialogs, + p_dialog ); + } + else + p_dialog->i_status = UPDATED_DIALOG; + vlc_mutex_unlock( &p_interact->object_lock ); + + /// \todo Check that the initiating object is not dying + while( p_dialog->i_status != ANSWERED_DIALOG && + p_dialog->i_status != HIDING_DIALOG && + !p_dialog->p_parent->b_die ) + { + msleep( 100000 ); + } + /// \todo locking + if( p_dialog->p_parent->b_die ) + { + p_dialog->i_return = DIALOG_CANCELLED; + p_dialog->i_status = ANSWERED_DIALOG; + } + p_dialog->i_flags |= DIALOG_GOT_ANSWER; + return p_dialog->i_return; } /* Add a dialog to the queue and return */ static int intf_Send( interaction_t *p_interact, interaction_dialog_t *p_dialog ) { + int i; + vlc_bool_t b_found = VLC_FALSE; vlc_mutex_lock( &p_interact->object_lock ); - /// \todo Check first it does not exist !!! - INSERT_ELEM( p_interact->pp_dialogs, - p_interact->i_dialogs, - p_interact->i_dialogs, - p_dialog ); + for( i = 0 ; i< p_interact->i_dialogs; i++ ) + { + if( p_interact->pp_dialogs[i]->i_id == p_dialog->i_id ) + { + b_found = VLC_TRUE; + } + } + if( !b_found ) + { + INSERT_ELEM( p_interact->pp_dialogs, + p_interact->i_dialogs, + p_interact->i_dialogs, + p_dialog ); + } + else + p_dialog->i_status = UPDATED_DIALOG; vlc_mutex_unlock( &p_interact->object_lock ); return VLC_SUCCESS; } @@ -362,6 +475,8 @@ static interaction_dialog_t *intf_InteractionGetById( vlc_object_t* p_this, interaction_t *p_interaction = intf_InteractionGet( p_this ); int i; + if( !p_interaction ) return NULL; + for( i = 0 ; i< p_interaction->i_dialogs; i++ ) { if( p_interaction->pp_dialogs[i]->i_id == i_id )