[vlc-devel] [RFC PATCH 2/5] dialog: rework API

Thomas Guillem thomas at gllm.fr
Fri Jan 29 12:06:28 CET 2016


New version: fix comment typos, simplify pf_cancel callback

This reworks the vlc dialog api:

 - dialog_Question is replaced by vlc_dialog_wait_question
 - dialog_Login is replaced by vlc_dialog_wait_login
 - dialog_Progress is replace by vlc_dialog_display_progress
 - dialog_Fatal is replaced by vlc_dialog_display_error
 - dialog_FatalWait is replaced by vlc_dialog_wait_question with i_type ==
   VLC_DIALOG_QUESTION_CRITICAL and without action1/action2

 - All dialogs (except vlc_dialog_display_error that returns immediatly) are
   interruptible via vlc_interrupt.

 - Nothing prevents to have more than one dialog type displayed at a time.
---
 include/vlc_dialog.h                              | 446 +++++++++---
 include/vlc_objects.h                             |   2 +
 modules/access/dvb/scan.c                         |  43 +-
 modules/access_output/file.c                      |  12 +-
 modules/codec/libass.c                            |  18 +-
 modules/demux/avi/avi.c                           |  48 +-
 modules/gui/qt4/dialogs/external.cpp              | 401 ++++++----
 modules/gui/qt4/dialogs/external.hpp              | 126 +++-
 modules/lua/extension.c                           |  57 +-
 modules/lua/extension.h                           |   2 +-
 modules/lua/extension_thread.c                    |   6 +-
 modules/misc/gnutls.c                             |  28 +-
 modules/misc/securetransport.c                    |  10 +-
 modules/text_renderer/freetype/fonts/fontconfig.c |  22 +-
 src/interface/dialog.c                            | 844 +++++++++++++++++-----
 src/libvlc.c                                      |  11 +
 src/libvlc.h                                      |   4 +-
 src/libvlccore.sym                                |  31 +-
 src/misc/keystore.c                               |  37 +-
 src/misc/update.c                                 |  58 +-
 test/modules/misc/tls.c                           |  33 +-
 21 files changed, 1605 insertions(+), 634 deletions(-)

diff --git a/include/vlc_dialog.h b/include/vlc_dialog.h
index 27eacd8..4dd13ba 100644
--- a/include/vlc_dialog.h
+++ b/include/vlc_dialog.h
@@ -18,119 +18,389 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
+/**
+ * @file
+ * This file declares VLC dialog API
+ */
+
 #ifndef VLC_DIALOG_H_
 #define VLC_DIALOG_H_
 # include <stdarg.h>
 
+typedef struct vlc_dialog_provider vlc_dialog_provider;
+typedef struct vlc_dialog_id vlc_dialog_id;
+
+
+/* Called from src/libvlc.c */
+vlc_dialog_provider *
+vlc_dialog_provider_new(void);
+
+/* Called from src/libvlc.c */
+void
+vlc_dialog_provider_release(vlc_dialog_provider *p_provider);
+
 /**
- * \ingroup interaction
+ * @defgroup vlc_dialog VLC dialog API
+ * @{
+ * @defgroup vlc_dialog_api API to interract with the user
  * @{
- * \file vlc_dialog.h
- * User interaction dialog APIs
  */
 
 /**
- * A fatal error dialog.
- * No response expected from the user.
+ * Dialog question type, see vlc_dialog_wait_question()
  */
-typedef struct dialog_fatal_t
+typedef enum vlc_dialog_question_type
 {
-    const char *title;
-    const char *message;
-} dialog_fatal_t;
+    VLC_DIALOG_QUESTION_NORMAL,
+    VLC_DIALOG_QUESTION_WARNING,
+    VLC_DIALOG_QUESTION_CRITICAL,
+} vlc_dialog_question_type;
 
-VLC_API void dialog_VFatal(vlc_object_t *, bool, const char *, const char *, va_list);
+/**
+ * Sends an error message
+ *
+ * This function returns immediately
+ *
+ * @param p_obj the VLC object emitting the error
+ * @param psz_title title of the error dialog
+ * @param psz_fmt format string for the error message
+ * @return VLC_SUCCESS on success, or a VLC error code on error
+ */
+VLC_API int
+vlc_dialog_display_error(vlc_object_t *p_obj, const char *psz_title,
+                         const char *psz_fmt, ...) VLC_FORMAT(3,4);
+#define vlc_dialog_display_error(a, b, c, ...) \
+    vlc_dialog_display_error(VLC_OBJECT(a), b, c, ##__VA_ARGS__)
 
-static inline VLC_FORMAT(3, 4)
-void dialog_Fatal (vlc_object_t *obj, const char *title, const char *fmt, ...)
-{
-     va_list ap;
+/**
+ * Sends an error message
+ *
+ * Equivalent to vlc_dialog_display_error() expect that it's called with a
+ * va_list.
+ */
+VLC_API int
+vlc_dialog_display_error_va(vlc_object_t *p_obj, const char *psz_title,
+                            const char *psz_fmt, va_list ap);
+/* TODO s/dialog_Fatal/vlc_dialog_display_error/g if accepted */
+#define dialog_Fatal vlc_dialog_display_error
 
-     va_start (ap, fmt);
-     dialog_VFatal(obj, false, title, fmt, ap);
-     va_end (ap);
-}
-#define dialog_Fatal(o, t, ...) \
-        dialog_Fatal(VLC_OBJECT(o), t, __VA_ARGS__)
+/**
+ * Requests an user name and a password
+ *
+ * This function waits until the user dismisses the dialog or responds. It's
+ * interruptible via vlc_interrupt. In that case, vlc_dialog_cbs.pf_cancel()
+ * will be invoked. If p_store is not NULL, the user will be asked to store the
+ * password or not.
+ *
+ * @param p_obj the VLC object emitting the dialog
+ * @param ppsz_username a pointer to the user name provided by the user, it
+ * must be freed with free() on success
+ * @param ppsz_password a pointer to the password provided by the user, it must
+ * be freed with free() on success
+ * @param p_store a pointer to the store answer provided by the user (optional)
+ * @param psz_title title of the login dialog
+ * @param psz_fmt format string for the login message
+ * @return < 0 on error, 0 if the user cancelled it, and 1 if ppsz_username and
+ * ppsz_password are valid.
+ */
+VLC_API int
+vlc_dialog_wait_login(vlc_object_t *p_obj, char **ppsz_username,
+                      char **ppsz_password, bool *p_store,
+                      const char *psz_default_username,
+                      const char *psz_title, const char *psz_fmt, ...)
+                      VLC_FORMAT(7,8);
+#define vlc_dialog_wait_login(a, b, c, d, e, f, g, ...) \
+    vlc_dialog_wait_login(VLC_OBJECT(a), b, c, d, e, f, g, ##__VA_ARGS__)
 
-static inline VLC_FORMAT(3, 4)
-void dialog_FatalWait (vlc_object_t *obj, const char *title,
-                       const char *fmt, ...){
-     va_list ap;
+/**
+ * Requests an user name and a password
+ *
+ * Equivalent to vlc_dialog_wait_login() expect that it's called with a
+ * va_list.
+ */
+VLC_API int
+vlc_dialog_wait_login_va(vlc_object_t *p_obj, char **ppsz_username,
+                         char **ppsz_password, bool *p_store,
+                         const char *psz_default_username,
+                         const char *psz_title, const char *psz_fmt, va_list ap);
 
-     va_start (ap, fmt);
-     dialog_VFatal(obj, true, title, fmt, ap);
-     va_end (ap);
-}
-#define dialog_FatalWait(o, t, ...) \
-        dialog_FatalWait(VLC_OBJECT(o), t, __VA_ARGS__)
+/**
+ * Asks a total (Yes/No/Cancel) question
+ *
+ * This function waits until the user dismisses the dialog or responds. It's
+ * interruptible via vlc_interrupt. In that case, vlc_dialog_cbs.pf_cancel()
+ * will be invoked. The psz_cancel is mandatory since this dialog is always
+ * cancellable by the user.
+ *
+ * @param p_obj the VLC object emitting the dialog
+ * @param i_type question type (severity of the question)
+ * @param psz_cancel text of the cancel button
+ * @param psz_action1 first choice/button text (optional)
+ * @param psz_action2 second choice/button text (optional)
+ * @param psz_title title of the question dialog
+ * @param psz_fmt format string for the question message
+ * @return < 0 on error, 0 if the user cancelled it, 1 on action1, 2 on action2
+ */
+VLC_API int
+vlc_dialog_wait_question(vlc_object_t *p_obj,
+                         vlc_dialog_question_type i_type,
+                         const char *psz_cancel, const char *psz_action1,
+                         const char *psz_action2, const char *psz_title,
+                         const char *psz_fmt, ...) VLC_FORMAT(7,8);
+#define vlc_dialog_wait_question(a, b, c, d, e, f, g, ...) \
+    vlc_dialog_wait_question(VLC_OBJECT(a), b, c, d, e, f, g, ##__VA_ARGS__)
 
 /**
- * A login dialog.
+ * Asks a total (Yes/No/Cancel) question
+ *
+ * Equivalent to vlc_dialog_wait_question() expect that it's called with a
+ * va_list.
  */
-typedef struct dialog_login_t
-{
-    const char *title;
-    const char *message;
-    const char *default_username;
-    char **username;
-    char **password;
-    /* if store is NULL, password can't be stored (there is no keystore) */
-    bool *store;
-} dialog_login_t;
+VLC_API int
+vlc_dialog_wait_question_va(vlc_object_t *p_obj,
+                            vlc_dialog_question_type i_type,
+                            const char *psz_cancel, const char *psz_action1,
+                            const char *psz_action2, const char *psz_title,
+                            const char *psz_fmt, va_list ap);
+
+/**
+ * Display a progress dialog
+ *
+ * This function returns immediately
+ *
+ * @param p_obj the VLC object emitting the dialog
+ * @param b_indeterminate true if the progress dialog is indeterminate
+ * @param f_position initial position of the progress bar (between 0.0 and 1.0)
+ * @param psz_cancel text of the cancel button, if NULL the dialog is not
+ * cancellable (optional)
+ * @param psz_title title of the progress dialog
+ * @param psz_fmt format string for the progress message
+ * @return a valid vlc_dialog_id on success, must be released with
+ * vlc_dialog_id_release()
+ */
+VLC_API vlc_dialog_id *
+vlc_dialog_display_progress(vlc_object_t *p_obj, bool b_indeterminate,
+                            float f_position, const char *psz_cancel,
+                            const char *psz_title, const char *psz_fmt, ...)
+                            VLC_FORMAT(6,7);
+#define vlc_dialog_display_progress(a, b, c, d, e, f, ...) \
+    vlc_dialog_display_progress(VLC_OBJECT(a), b, c, d, e, f, ##__VA_ARGS__)
 
-VLC_API void dialog_Login(vlc_object_t *, const char *, char **, char **, bool *, const char *, const char *, ...) VLC_FORMAT (7, 8);
-#define dialog_Login(o, u, p, s, t, v, w, ...) \
-        dialog_Login(VLC_OBJECT(o), u, p, s, t, v, w, __VA_ARGS__)
+/**
+ * Display a progress dialog
+ *
+ * Equivalent to vlc_dialog_display_progress() expect that it's called with a
+ * va_list.
+ */
+VLC_API vlc_dialog_id *
+vlc_dialog_display_progress_va(vlc_object_t *p_obj, bool b_indeterminate,
+                               float f_position, const char *psz_cancel,
+                               const char *psz_title, const char *psz_fmt,
+                               va_list ap);
 
-VLC_API void dialog_vaLogin(vlc_object_t *, const char *, char **, char **, bool *, const char *, const char *, va_list args);
-#define dialog_vaLogin(o, u, p, s, t, v, w, x) \
-        dialog_vaLogin(VLC_OBJECT(o), u, p, s, t, v, w, x)
+/**
+ * Update the position of the progress dialog
+ *
+ * @param f_position position of the progress bar (between 0.0 and 1.0)
+ * @return VLC_SUCCESS on success, or a VLC error code on error
+ */
+VLC_API int
+vlc_dialog_id_update_progress(vlc_dialog_id *p_id, float f_position);
 
+/**
+ * Update the position and the message of the progress dialog
+ *
+ * @param f_position position of the progress bar (between 0.0 and 1.0)
+ * @param psz_fmt format string for the progress message
+ * @return VLC_SUCCESS on success, or a VLC error code on error
+ */
+VLC_API int
+vlc_dialog_id_update_progress_text(vlc_dialog_id *p_id, float f_position,
+                                   const char *psz_fmt, ...);
 
 /**
- * A question dialog.
+ * Update the position and the message of the progress dialog
+ *
+ * Equivalent to vlc_dialog_id_update_progress_text() expect that it's called
+ * with a va_list.
  */
-typedef struct dialog_question_t
+VLC_API int
+vlc_dialog_id_update_progress_text_va(vlc_dialog_id *p_id, float f_position,
+                                      const char *psz_fmt, va_list ap);
+
+/**
+ * Release the dialog id returned by vlc_dialog_display_progress(), causes the
+ * vlc_dialog_cbs.pf_cancel() callback to be invoked.
+ */
+VLC_API void
+vlc_dialog_id_release(vlc_dialog_id *p_id);
+
+/**
+ * Return true if the dialog id is cancelled
+ */
+VLC_API bool
+vlc_dialog_id_is_cancelled(vlc_dialog_id *p_id);
+
+/**
+ * @}
+ * @defgroup vlc_dialog_implementation Implemented by GUI modules or libvlc
+ * @{
+ */
+
+typedef enum vlc_dialog_type
+{
+    VLC_DIALOG_ERROR,
+    VLC_DIALOG_LOGIN,
+    VLC_DIALOG_QUESTION,
+    VLC_DIALOG_PROGRESS,
+} vlc_dialog_type;
+
+/** Dialog to be displayed */
+typedef struct vlc_dialog
 {
-    const char *title;
-    const char *message;
-    const char *yes;
-    const char *no;
-    const char *cancel;
-    int answer;
-} dialog_question_t;
-
-VLC_API int dialog_Question(vlc_object_t *, const char *, const char *,
-                            const char *, const char *, const char *, ...)
-VLC_FORMAT(3, 7);
-#define dialog_Question(o, t, m, y, n, ...) \
-        dialog_Question(VLC_OBJECT(o), t, m, y, n, __VA_ARGS__)
-
-typedef struct dialog_progress_bar_t
-{   /* Request-time parameters */
-    const char *title;
-    const char *message;
-    const char *cancel;
-    /* Permanent parameters */
-    void (*pf_update) (void *, const char *, float);
-    bool (*pf_check) (void *);
-    void (*pf_destroy) (void *);
-    void *p_sys;
-} dialog_progress_bar_t;
-
-VLC_API dialog_progress_bar_t * dialog_ProgressCreate(vlc_object_t *, const char *, const char *, const char *) VLC_USED;
-#define dialog_ProgressCreate(o, t, m, c) \
-        dialog_ProgressCreate(VLC_OBJECT(o), t, m, c)
-VLC_API void dialog_ProgressDestroy(dialog_progress_bar_t *);
-VLC_API void dialog_ProgressSet(dialog_progress_bar_t *, const char *, float);
-VLC_API bool dialog_ProgressCancelled(dialog_progress_bar_t *);
-
-VLC_API int dialog_Register(vlc_object_t *);
-VLC_API int dialog_Unregister(vlc_object_t *);
-#define dialog_Register(o) dialog_Register(VLC_OBJECT(o))
-#define dialog_Unregister(o) dialog_Unregister(VLC_OBJECT(o))
-
-/** @} */
+    vlc_dialog_type i_type;
+    /** title of the dialog */
+    const char *psz_title;
+    /** text of the dialog */
+    const char *psz_text;
+
+    union
+    {
+        /** if i_type == VLC_DIALOG_LOGIN */
+        struct
+        {
+            /** default user name that should be set on the user form */
+            const char *psz_default_username;
+            /** if true, ask the user if he wants to save the credentials */
+            bool b_ask_store;
+        } login;
+        /** if i_type == VLC_DIALOG_QUESTION */
+        struct
+        {
+            /** question type (or severity) of the dialog */
+            vlc_dialog_question_type i_type;
+            /** text of the cancel button */
+            const char *psz_cancel;
+            /** text of the first button (optional) */
+            const char *psz_action1;
+            /** text of the second button (optional) */
+            const char *psz_action2;
+        } question;
+        /** if i_type == VLC_DIALOG_PROGRESS */
+        struct
+        {
+            /** true if the progress dialog is indeterminate */
+            bool b_indeterminate;
+            /** initial position of the progress bar (between 0.0 and 1.0) */
+            float f_position;
+            /** text of the cancel button, if NULL the dialog is not
+             * cancellable (optional) */
+            const char *psz_cancel;
+        } progress;
+    } u;
+} vlc_dialog;
+
+/**
+ * Dialog callbacks to be implemented
+ *
+ * pf_display and pf_cancel are mandatory.
+ */
+typedef struct vlc_dialog_cbs
+{
+    /**
+     * Called when a new dialog needs to be displayed
+     *
+     * @param p_id id used to interact with the dialog, can be null (for the
+     * VLC_DIALOG_ERROR case)
+     * @param p_dialog all informations that need to be displayed
+     * @param p_data opaque pointer for the callback
+     * @return true if the dialog is handled by the callback, false otherwise
+     */
+    bool (*pf_display)(vlc_dialog_id *p_id, vlc_dialog *p_dialog, void *p_data);
+    /**
+     * Called when a displayed dialog needs to be cancelled
+     *
+     * The implementation must call vlc_dialog_id_dismiss() to really release
+     * the dialog.
+     *
+     * @param p_id id of the dialog
+     * @param p_data opaque pointer for the callback
+     */
+    void (*pf_cancel)(vlc_dialog_id *p_id, void *p_data);
+    /**
+     * Called when a progress dialog needs to be updated (optional)
+     *
+     * @param p_id id of the dialog
+     * @param f_position osition of the progress bar (between 0.0 and 1.0)
+     * @param psz_text new text of the progress dialog
+     * @param p_data opaque pointer for the callback
+     */
+    void (*pf_update_progress)(vlc_dialog_id *p_id, float f_position,
+                               const char *psz_text, void *p_data);
+} vlc_dialog_cbs;
+
+/**
+ * Register callbacks for the VLC dialog
+ *
+ * @param p_cbs a pointer to callbacks, or NULL to unregister callbacks.
+ * @param p_data opaque pointer for the callback
+ */
+VLC_API void
+vlc_dialog_provider_set_callbacks(vlc_object_t *p_obj,
+                                  vlc_dialog_cbs *p_cbs, void *p_data);
+#define vlc_dialog_provider_set_callbacks(a, b, c) \
+    vlc_dialog_provider_set_callbacks(VLC_OBJECT(a), b, c)
+
+/**
+ * Associate an opaque pointer with the dialog id
+ */
+VLC_API void
+vlc_dialog_id_set_context(vlc_dialog_id *p_id, void *p_context);
+
+/**
+ * Return the opaque pointer associated with the dialog id
+ */
+VLC_API void *
+vlc_dialog_id_get_context(vlc_dialog_id *p_id);
+
+/**
+ * Post a login answer
+ *
+ * After this call, p_id won't be valid anymore
+ *
+ * @param p_id id of the dialog
+ * @param psz_username valid and non empty string
+ * @param psz_password valid string (can be empty)
+ * @param b_store if true, store the credentials
+ * @return VLC_SUCCESS on success, or a VLC error code on error
+ */
+VLC_API int
+vlc_dialog_id_post_login(vlc_dialog_id *p_id, const char *psz_username,
+                         const char *psz_password, bool b_store);
+
+/**
+ * Post a question answer
+ *
+ * After this call, p_id won't be valid anymore
+ *
+ * @param p_id id of the dialog
+ * @param i_action 1 or action1, 2 for action2
+ * @return VLC_SUCCESS on success, or a VLC error code on error
+ */
+VLC_API int
+vlc_dialog_id_post_action(vlc_dialog_id *p_id, int i_action);
+
+/**
+ * Dismiss a dialog
+ *
+ * After this call, p_id won't be valid anymore
+ *
+ * @param p_id id of the dialog
+ * @return VLC_SUCCESS on success, or a VLC error code on error
+ */
+VLC_API int
+vlc_dialog_id_dismiss(vlc_dialog_id *p_id);
+
+/** @} @} */
 
 #endif
diff --git a/include/vlc_objects.h b/include/vlc_objects.h
index 598313e..12f754a 100644
--- a/include/vlc_objects.h
+++ b/include/vlc_objects.h
@@ -41,6 +41,8 @@ struct vlc_object_t
     VLC_COMMON_MEMBERS
 };
 
+typedef struct vlc_dialog_provider vlc_dialog_provider;
+
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
diff --git a/modules/access/dvb/scan.c b/modules/access/dvb/scan.c
index f12d015..c6b7894 100644
--- a/modules/access/dvb/scan.c
+++ b/modules/access/dvb/scan.c
@@ -87,7 +87,7 @@ typedef struct
 struct scan_t
 {
     vlc_object_t *p_obj;
-    struct dialog_progress_bar_t *p_dialog;
+    vlc_dialog_id *p_dialog_id;
     uint64_t i_index;
     scan_parameter_t parameter;
     int64_t i_time_start;
@@ -212,7 +212,7 @@ scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
 
     p_scan->p_obj = VLC_OBJECT(p_obj);
     p_scan->i_index = 0;
-    p_scan->p_dialog = NULL;
+    p_scan->p_dialog_id = NULL;
     TAB_INIT( p_scan->i_service, p_scan->pp_service );
     p_scan->parameter = *p_parameter;
     p_scan->i_time_start = mdate();
@@ -222,8 +222,8 @@ scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
 
 void scan_Destroy( scan_t *p_scan )
 {
-    if( p_scan->p_dialog != NULL )
-        dialog_ProgressDestroy( p_scan->p_dialog );
+    if( p_scan->p_dialog_id != NULL )
+        vlc_dialog_id_release( p_scan->p_dialog_id );
 
     for( int i = 0; i < p_scan->i_service; i++ )
         scan_service_Delete( p_scan->pp_service[i] );
@@ -647,7 +647,6 @@ int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
     if( i_ret )
         return i_ret;
 
-    char *psz_text;
     int i_service = 0;
 
     for( int i = 0; i < p_scan->i_service; i++ )
@@ -658,18 +657,28 @@ int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
 
     const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
     char psz_eta[MSTRTIME_MAX_SIZE];
+    const char *psz_fmt = _("%.1f MHz (%d services)\n~%s remaining");
 
-    if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
-                  (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
+    if( i_eta >= 0 )
+        msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
+
+    if( p_scan->p_dialog_id == NULL )
     {
-        if( i_eta >= 0 )
-            msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
-
-        if( p_scan->p_dialog == NULL )
-            p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
-        if( p_scan->p_dialog != NULL )
-            dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
-        free( psz_text );
+        p_scan->p_dialog_id =
+            vlc_dialog_display_progress( p_scan->p_obj, false,
+                                         f_position, _("Cancel"),
+                                         _("Scanning DVB"), psz_fmt,
+                                         (double)p_cfg->i_frequency / 1000000,
+                                         i_service,
+                                         secstotimestr( psz_eta, i_eta/1000000 ) );
+    }
+    else
+    {
+        vlc_dialog_id_update_progress_text( p_scan->p_dialog_id,
+                                            f_position, psz_fmt,
+                                            (double)p_cfg->i_frequency / 1000000,
+                                            i_service,
+                                            secstotimestr( psz_eta, i_eta/1000000 ) );
     }
 
     p_scan->i_index++;
@@ -678,7 +687,9 @@ int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
 
 bool scan_IsCancelled( scan_t *p_scan )
 {
-    return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
+    if( p_scan->p_dialog_id == NULL )
+        return false;
+    return vlc_dialog_id_is_cancelled( p_scan->p_dialog_id );
 }
 
 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
diff --git a/modules/access_output/file.c b/modules/access_output/file.c
index 2e61e32..34a0329 100644
--- a/modules/access_output/file.c
+++ b/modules/access_output/file.c
@@ -318,12 +318,12 @@ static int Open( vlc_object_t *p_this )
                 break;
             flags &= ~O_EXCL;
         }
-        while (dialog_Question (p_access, path,
-                                _("The output file already exists. "
-                                "If recording continues, the file will be "
-                                "overridden and its content will be lost."),
-                                _("Keep existing file"),
-                                _("Overwrite"), NULL) == 2);
+        while (vlc_dialog_wait_question (p_access, VLC_DIALOG_QUESTION_NORMAL,
+                                         _("Keep existing file"),
+                                         _("Overwrite"), NULL, path,
+                                         _("The output file already exists. "
+                                         "If recording continues, the file will be "
+                                         "overridden and its content will be lost.")) == 1);
         free (buf);
         if (fd == -1)
             return VLC_EGENERIC;
diff --git a/modules/codec/libass.c b/modules/codec/libass.c
index 77240e7..920148a 100644
--- a/modules/codec/libass.c
+++ b/modules/codec/libass.c
@@ -225,19 +225,17 @@ static int Create( vlc_object_t *p_this )
 
 #ifdef HAVE_FONTCONFIG
 #if defined(_WIN32)
-    dialog_progress_bar_t *p_dialog =
-        dialog_ProgressCreate( p_dec,
-                               _("Building font cache"),
-                               _( "Please wait while your font cache is rebuilt.\n"
-                                  "This should take less than a minute." ), NULL );
+    int i_ret =
+        vlc_dialog_display_progress( p_dec, true, 0.0, NULL,
+                                    _("Building font cache"),
+                                    _( "Please wait while your font cache is rebuilt.\n"
+                                    "This should take less than a minute." ) );
+    unsigned int i_dialog_id = i_ret > 0 ? i_ret : 0;
 #endif
     ass_set_fonts( p_renderer, psz_font, psz_family, 1, NULL, 1 );  // setup default font/family
 #if defined(_WIN32)
-    if( p_dialog )
-    {
-        dialog_ProgressSet( p_dialog, NULL, 1.0 );
-        dialog_ProgressDestroy( p_dialog );
-    }
+    if( i_dialog_id != 0 )
+        vlc_dialog_cancel( p_dec, i_dialog_id );
 #endif
 #else
     ass_set_fonts( p_renderer, psz_font, psz_family, 1, NULL, 1 );
diff --git a/modules/demux/avi/avi.c b/modules/demux/avi/avi.c
index 425748a..fd41f03 100644
--- a/modules/demux/avi/avi.c
+++ b/modules/demux/avi/avi.c
@@ -753,22 +753,28 @@ aviindex:
             }
             if( i_do_index == 0 )
             {
-                switch( dialog_Question( p_demux, _("Broken or missing AVI Index") ,
-                   _( "Because this AVI file index is broken or missing, "
-                      "seeking will not work correctly.\n"
-                      "VLC won't repair your file but can temporary fix this "
-                      "problem by building an index in memory.\n"
-                      "This step might take a long time on a large file.\n"
-                      "What do you want to do?" ),
-                      _( "Build index then play" ), _( "Play as is" ), _( "Do not play") ) )
+                const char *psz_msg = _(
+                    "Because this AVI file index is broken or missing, "
+                    "seeking will not work correctly.\n"
+                    "VLC won't repair your file but can temporary fix this "
+                    "problem by building an index in memory.\n"
+                    "This step might take a long time on a large file.\n"
+                    "What do you want to do?");
+                switch( vlc_dialog_wait_question( p_demux,
+                                                  VLC_DIALOG_QUESTION_NORMAL,
+                                                  _("Do not play"),
+                                                  _("Build index then play"),
+                                                  _("Play as is"),
+                                                  _("Broken or missing AVI Index"),
+                                                  "%s", psz_msg ) )
                 {
+                    case 0:
+                        b_aborted = true;
+                        goto error;
                     case 1:
                         b_index = true;
                         msg_Dbg( p_demux, "Fixing AVI index" );
                         goto aviindex;
-                    case 3:
-                        b_aborted = true;
-                        goto error;
                 }
             }
             else
@@ -2609,7 +2615,7 @@ static void AVI_IndexCreate( demux_t *p_demux )
     off_t i_movi_end;
 
     mtime_t i_dialog_update;
-    dialog_progress_bar_t *p_dialog = NULL;
+    vlc_dialog_id *p_dialog_id = NULL;
 
     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
     p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
@@ -2633,23 +2639,27 @@ static void AVI_IndexCreate( demux_t *p_demux )
     /* Only show dialog if AVI is > 10MB */
     i_dialog_update = mdate();
     if( stream_Size( p_demux->s ) > 10000000 )
-        p_dialog = dialog_ProgressCreate( p_demux, _("Fixing AVI Index..."),
-                                       NULL, _("Cancel") );
+    {
+        p_dialog_id =
+            vlc_dialog_display_progress( p_demux, false, 0.0, _("Cancel"),
+                                         _("Broken or missing AVI Index"),
+                                         _("Fixing AVI Index...") );
+    }
 
     for( ;; )
     {
         avi_packet_t pk;
 
         /* Don't update/check dialog too often */
-        if( p_dialog && mdate() - i_dialog_update > 100000 )
+        if( p_dialog_id != NULL && mdate() - i_dialog_update > 100000 )
         {
-            if( dialog_ProgressCancelled( p_dialog ) )
+            if( vlc_dialog_id_is_cancelled( p_dialog_id ) )
                 break;
 
             double f_current = stream_Tell( p_demux->s );
             double f_size    = stream_Size( p_demux->s );
             double f_pos     = f_current / f_size;
-            dialog_ProgressSet( p_dialog, NULL, f_pos );
+            vlc_dialog_id_update_progress( p_dialog_id, f_pos );
 
             i_dialog_update = mdate();
         }
@@ -2714,8 +2724,8 @@ static void AVI_IndexCreate( demux_t *p_demux )
     }
 
 print_stat:
-    if( p_dialog != NULL )
-        dialog_ProgressDestroy( p_dialog );
+    if( p_dialog_id != NULL )
+        vlc_dialog_id_release( p_dialog_id );
 
     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
     {
diff --git a/modules/gui/qt4/dialogs/external.cpp b/modules/gui/qt4/dialogs/external.cpp
index 9c7ebfd..85d3912 100644
--- a/modules/gui/qt4/dialogs/external.cpp
+++ b/modules/gui/qt4/dialogs/external.cpp
@@ -23,96 +23,171 @@
 # include <config.h>
 #endif
 
-//#include "qt4.hpp"
 #include "external.hpp"
 #include "errors.hpp"
-#include <vlc_dialog.h>
 
-#include <QDialog>
+#include <assert.h>
+
 #include <QCheckBox>
 #include <QDialogButtonBox>
 #include <QLabel>
 #include <QLineEdit>
 #include <QMessageBox>
 #include <QProgressDialog>
-#include <QMutex>
 #include <QPushButton>
-#include <QTimer>
 
 DialogHandler::DialogHandler (intf_thread_t *p_intf, QObject *_parent)
-    : QObject( _parent ), p_intf (p_intf),
-      critical (VLC_OBJECT(p_intf), "dialog-critical"),
-      login (VLC_OBJECT(p_intf), "dialog-login"),
-      question (VLC_OBJECT(p_intf), "dialog-question"),
-      progressBar (VLC_OBJECT(p_intf), "dialog-progress-bar")
+    : QObject( _parent ), p_intf (p_intf)
+{
+    vlc_dialog_cbs cbs = {
+        displayCb,
+        cancelCb,
+        updateProgressCb
+    };
+    vlc_dialog_provider_set_callbacks(p_intf, &cbs, this);
+
+    CONNECT(this, errorDisplayed(const QString &, const QString &),
+            this, displayError(const QString &, const QString &));
+
+    CONNECT(this, loginDisplayed(vlc_dialog_id *, const QString &,
+                                 const QString &, const QString &, bool),
+            this, displayLogin(vlc_dialog_id *, const QString &, const QString &,
+                               const QString &, bool));
+
+    CONNECT(this, questionDisplayed(vlc_dialog_id *, const QString &,
+                                    const QString &, int, const QString &,
+                                    const QString &, const QString &),
+            this, displayQuestion(vlc_dialog_id *, const QString &, const QString &,
+                                  int, const QString &, const QString &,
+                                  const QString &));
+
+    CONNECT(this, progressDisplayed(vlc_dialog_id *, const QString &, const QString &,
+                                    bool, float, const QString &),
+            this, displayProgress(vlc_dialog_id *, const QString &, const QString &,
+                                  bool, float, const QString &));
+
+    CONNECT(this, cancelled(vlc_dialog_id *), this, cancel(vlc_dialog_id *));
+
+    CONNECT(this, progressUpdated(vlc_dialog_id *, float, const QString &),
+            this, updateProgress(vlc_dialog_id *, float, const QString &));
+}
+
+DialogHandler::~DialogHandler()
 {
-    var_Create (p_intf, "dialog-error", VLC_VAR_ADDRESS);
-    var_AddCallback (p_intf, "dialog-error", error, this);
-    connect (this, SIGNAL(error(const QString &, const QString &)),
-             SLOT(displayError(const QString &, const QString &)));
-
-    critical.addCallback(this, SLOT(displayCritical(void *)),
-                         Qt::BlockingQueuedConnection);
-    login.addCallback(this, SLOT(requestLogin(void *)),
-                      Qt::BlockingQueuedConnection);
-    question.addCallback(this, SLOT(requestAnswer(void *)),
-                         Qt::BlockingQueuedConnection);
-    progressBar.addCallback(this, SLOT(startProgressBar(void *)),
-                            Qt::BlockingQueuedConnection);
-
-    dialog_Register (p_intf);
+    vlc_dialog_provider_set_callbacks(p_intf, NULL, NULL);
 }
 
-DialogHandler::~DialogHandler (void)
+bool DialogHandler::displayCb(vlc_dialog_id *p_id, vlc_dialog *p_dialog,
+                              void *p_data)
 {
-    dialog_Unregister (p_intf);
+    DialogHandler *self =  static_cast<DialogHandler *>(p_data);
+    const QString title = qfu(p_dialog->psz_title);
+    const QString text = qfu(p_dialog->psz_text);
 
-    var_DelCallback (p_intf, "dialog-error", error, this);
-    var_Destroy (p_intf, "dialog-error");
+    switch (p_dialog->i_type)
+    {
+        case VLC_DIALOG_ERROR:
+            emit self->errorDisplayed(title, text);
+            break;
+        case VLC_DIALOG_LOGIN:
+        {
+            assert(p_id != NULL);
+            const QString defaultUsername =
+                p_dialog->u.login.psz_default_username != NULL ?
+                qfu(p_dialog->u.login.psz_default_username) : QString();
+
+            emit self->loginDisplayed(p_id, title, text, defaultUsername,
+                                      p_dialog->u.login.b_ask_store);
+            break;
+        }
+        case VLC_DIALOG_QUESTION:
+        {
+            assert(p_id != NULL);
+            const QString cancel = qfu(p_dialog->u.question.psz_cancel);
+            const QString action1 = p_dialog->u.question.psz_action1 != NULL ?
+                qfu(p_dialog->u.question.psz_action1) : QString();
+            const QString action2 = p_dialog->u.question.psz_action2 != NULL ?
+                qfu(p_dialog->u.question.psz_action2) : QString();
+
+            emit self->questionDisplayed(p_id, title, text,
+                                         p_dialog->u.question.i_type,
+                                         cancel, action1, action2);
+            break;
+        }
+        case VLC_DIALOG_PROGRESS:
+        {
+            assert(p_id != NULL);
+            const QString cancel = p_dialog->u.progress.psz_cancel != NULL ?
+                qfu(p_dialog->u.progress.psz_cancel) : QString();
+            emit self->progressDisplayed(p_id, title, text,
+                                         p_dialog->u.progress.b_indeterminate,
+                                         p_dialog->u.progress.f_position, cancel);
+            break;
+        }
+    }
+    return true;
 }
 
-int DialogHandler::error (vlc_object_t *obj, const char *,
-                          vlc_value_t, vlc_value_t value, void *data)
+void DialogHandler::cancelCb(vlc_dialog_id *p_id, void *p_data)
 {
-    const dialog_fatal_t *dialog = (const dialog_fatal_t *)value.p_address;
-    DialogHandler *self = static_cast<DialogHandler *>(data);
+    DialogHandler *self = static_cast<DialogHandler *>(p_data);
+    emit self->cancelled(p_id);
+}
 
-    if (var_InheritBool (obj, "qt-error-dialogs"))
-        emit self->error (qfu(dialog->title), qfu(dialog->message));
-    return VLC_SUCCESS;
+void DialogHandler::updateProgressCb(vlc_dialog_id *p_id, float f_value,
+                                     const char *psz_text, void *p_data)
+{
+    DialogHandler *self = static_cast<DialogHandler *>(p_data);
+    emit self->progressUpdated(p_id, f_value, qfu(psz_text));
 }
 
-void DialogHandler::displayError (const QString& title, const QString& message)
+void DialogHandler::cancel(vlc_dialog_id *p_id)
 {
-    ErrorsDialog::getInstance (p_intf)->addError(title, message);
+    DialogWrapper *p_wrapper =
+        static_cast<DialogWrapper *>(vlc_dialog_id_get_context(p_id));
+    if (p_wrapper != NULL)
+        p_wrapper->finish(QDialog::Rejected);
 }
 
-void DialogHandler::displayCritical (void *value)
+void DialogHandler::updateProgress(vlc_dialog_id *p_id, float f_value,
+                                   const QString &text)
 {
-    const dialog_fatal_t *dialog = (const dialog_fatal_t *)value;
+    DialogWrapper *p_wrapper =
+        static_cast<DialogWrapper *>(vlc_dialog_id_get_context(p_id));
 
-    QMessageBox::critical (NULL, qfu(dialog->title), qfu(dialog->message),
-                           QMessageBox::Ok);
+    ProgressDialogWrapper *p_progress_wrapper
+        = dynamic_cast<ProgressDialogWrapper *>(p_wrapper);
+
+    if (p_progress_wrapper != NULL)
+        p_progress_wrapper->updateProgress(f_value, text);
 }
 
-void DialogHandler::requestLogin (void *value)
+void DialogHandler::displayError(const QString &title, const QString &text)
 {
-    dialog_login_t *data = (dialog_login_t *)value;
-    QDialog *dialog = new QDialog;
+    ErrorsDialog::getInstance (p_intf)->addError(title, text);
+}
+
+void DialogHandler::displayLogin(vlc_dialog_id *p_id, const QString &title,
+                                 const QString &text,
+                                 const QString &defaultUsername,
+                                 bool b_ask_store)
+{
+    QDialog *dialog = new QDialog();
     QLayout *layout = new QVBoxLayout (dialog);
 
-    dialog->setWindowTitle (qfu(data->title));
+    dialog->setWindowTitle (title);
     dialog->setWindowRole ("vlc-login");
+    dialog->setModal(true);
     layout->setMargin (2);
 
     /* Username and password fields */
     QWidget *panel = new QWidget (dialog);
     QGridLayout *grid = new QGridLayout;
-    grid->addWidget (new QLabel (qfu(data->message)), 0, 0, 1, 2);
+    grid->addWidget (new QLabel (text), 0, 0, 1, 2);
 
     QLineEdit *userLine = new QLineEdit;
-    if (data->default_username != NULL)
-        userLine->setText(qtr(data->default_username));
+    if (!defaultUsername.isEmpty())
+        userLine->setText(defaultUsername);
     grid->addWidget (new QLabel (qtr("Username")), 1, 0);
     grid->addWidget (userLine, 1, 1);
 
@@ -122,7 +197,7 @@ void DialogHandler::requestLogin (void *value)
     grid->addWidget (passLine, 2, 1);
 
     QCheckBox *checkbox = NULL;
-    if (data->store != NULL)
+    if (b_ask_store)
     {
         checkbox = new QCheckBox;
         checkbox->setChecked (getSettings()->value ("store_password", true).toBool ());
@@ -134,7 +209,7 @@ void DialogHandler::requestLogin (void *value)
     layout->addWidget (panel);
 
     /* focus on passLine if the username is already set */
-    if (data->default_username != NULL)
+    if (!defaultUsername.isEmpty())
         passLine->setFocus();
 
     /* OK, Cancel buttons */
@@ -148,126 +223,172 @@ void DialogHandler::requestLogin (void *value)
     CONNECT( buttonBox, rejected(), dialog, reject() );
     layout->addWidget (buttonBox);
 
-    /* Run the dialog */
     dialog->setLayout (layout);
+    vlc_dialog_id_set_context(p_id,
+        new LoginDialogWrapper(this, p_intf, p_id, dialog, userLine, passLine,
+                               checkbox));
+    dialog->show();
+}
 
-    if (dialog->exec ())
+void
+DialogHandler::displayQuestion(vlc_dialog_id *p_id, const QString &title,
+                               const QString &text, int i_type,
+                               const QString &cancel, const QString &action1,
+                               const QString &action2)
+{
+    enum QMessageBox::Icon icon;
+    switch (i_type)
     {
-        *data->username = strdup (qtu(userLine->text ()));
-        *data->password = strdup (qtu(passLine->text ()));
-        if (data->store != NULL)
-        {
-            *data->store = checkbox->isChecked ();
-            getSettings()->setValue ("store_password", *data->store);
-        }
+        case VLC_DIALOG_QUESTION_WARNING:
+            icon = QMessageBox::Warning;
+            break;
+        case VLC_DIALOG_QUESTION_CRITICAL:
+            icon = QMessageBox::Critical;
+            break;
+        default:
+        case VLC_DIALOG_QUESTION_NORMAL:
+            icon = action1.isEmpty() && action2.isEmpty() ?
+                 QMessageBox::Information : QMessageBox::Question;
+            break;
     }
+    QMessageBox *box = new QMessageBox (icon, title, text);
+    box->addButton ("&" + cancel, QMessageBox::RejectRole);
+    box->setModal(true);
+    QAbstractButton *action1Button = NULL;
+    if (!action1.isEmpty())
+        action1Button = box->addButton("&" + action1, QMessageBox::AcceptRole);
+    QAbstractButton *action2Button = NULL;
+    if (!action2.isEmpty())
+        action2Button = box->addButton("&" + action2, QMessageBox::AcceptRole);
+
+    vlc_dialog_id_set_context(p_id,
+        new QuestionDialogWrapper(this, p_intf, p_id, box, action1Button,
+                                  action2Button));
+    box->show();
+}
+
+void DialogHandler::displayProgress(vlc_dialog_id *p_id, const QString &title,
+                                    const QString &text, bool b_indeterminate,
+                                    float f_position, const QString &cancel)
+{
+    QProgressDialog *progress =
+        new QProgressDialog(text, cancel.isEmpty() ? QString() : "&" + cancel,
+                            0, b_indeterminate ? 0 : 1000);
+    progress->setWindowTitle(title);
+    if (!cancel.isEmpty())
+        progress->setModal(true);
     else
     {
-        *data->username = *data->password = NULL;
-        if (data->store != NULL)
-            *data->store = false;
+        /* not cancellable: remove close button */
+        progress->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+                                 Qt::CustomizeWindowHint);
     }
+    progress->setWindowRole ("vlc-progress");
+    progress->setValue(b_indeterminate ? 0 : f_position * 1000);
 
-    delete dialog;
+    vlc_dialog_id_set_context(p_id,
+        new ProgressDialogWrapper(this, p_intf, p_id, progress, b_indeterminate));
+
+    progress->show();
 }
 
-void DialogHandler::requestAnswer (void *value)
+DialogWrapper::DialogWrapper(DialogHandler *p_handler, intf_thread_t *p_intf,
+                             vlc_dialog_id *p_id, QDialog *p_dialog)
+    : QObject()
+    , p_handler(p_handler)
+    , p_intf(p_intf)
+    , p_id(p_id)
+    , p_dialog(p_dialog)
 {
-    dialog_question_t *data = (dialog_question_t *)value;
-
-    QMessageBox *box = new QMessageBox (QMessageBox::Question,
-                                        qfu(data->title), qfu(data->message));
-    QAbstractButton *yes = (data->yes != NULL)
-        ? box->addButton ("&" + qfu(data->yes), QMessageBox::YesRole) : NULL;
-    QAbstractButton *no = (data->no != NULL)
-        ? box->addButton ("&" + qfu(data->no), QMessageBox::NoRole) : NULL;
-    if (data->cancel != NULL)
-        box->addButton ("&" + qfu(data->cancel), QMessageBox::RejectRole);
-
-    box->exec ();
-
-    int answer;
-    if (box->clickedButton () == yes)
-        answer = 1;
-    else
-    if (box->clickedButton () == no)
-        answer = 2;
-    else
-        answer = 3;
-
-    delete box;
-    data->answer = answer;
+    CONNECT(p_dialog, finished(int), this, finish(int));
 }
 
-
-QVLCProgressDialog::QVLCProgressDialog (DialogHandler *parent,
-                                        struct dialog_progress_bar_t *data)
-    : QProgressDialog (qfu(data->message),
-                       data->cancel ? ("&" + qfu(data->cancel)) : 0, 0, 1000),
-      handler (parent),
-      cancelled (false)
+DialogWrapper::~DialogWrapper()
 {
-    if (data->cancel)
-        setWindowModality (Qt::ApplicationModal);
-    if (data->title != NULL)
-        setWindowTitle (qfu(data->title));
-
-    setWindowRole ("vlc-progress");
-    setValue( 0 );
-
-    connect (this, SIGNAL(progressed(int)), SLOT(setValue(int)));
-    connect (this, SIGNAL(described(const QString&)),
-                   SLOT(setLabelText(const QString&)));
-    connect (this, SIGNAL(canceled(void)), SLOT(saveCancel(void)));
-    connect (this, SIGNAL(released(void)), SLOT(deleteLater(void)));
-
-    data->pf_update = update;
-    data->pf_check = check;
-    data->pf_destroy = destroy;
-    data->p_sys = this;
+    p_dialog->hide();
+    delete p_dialog;
 }
 
-void QVLCProgressDialog::update (void *priv, const char *text, float value)
+void DialogWrapper::finish(int result)
 {
-    QVLCProgressDialog *self = static_cast<QVLCProgressDialog *>(priv);
-
-    if (text != NULL)
-        emit self->described (qfu(text));
-    emit self->progressed ((int)(value * 1000.));
+    if (result == QDialog::Rejected && p_id != NULL)
+    {
+        vlc_dialog_id_dismiss(p_id);
+        p_id = NULL;
+    }
+    deleteLater();
 }
 
-static QMutex cancel_mutex;
-
-bool QVLCProgressDialog::check (void *priv)
+LoginDialogWrapper::LoginDialogWrapper(DialogHandler *p_handler,
+                                       intf_thread_t *p_intf, vlc_dialog_id *p_id,
+                                       QDialog *p_dialog, QLineEdit *userLine,
+                                       QLineEdit *passLine, QCheckBox *checkbox)
+    : DialogWrapper(p_handler, p_intf, p_id, p_dialog)
+    , userLine(userLine)
+    , passLine(passLine)
+    , checkbox(checkbox)
 {
-    QVLCProgressDialog *self = static_cast<QVLCProgressDialog *>(priv);
-    QMutexLocker locker (&cancel_mutex);
-    return self->cancelled;
+    CONNECT(p_dialog, accepted(), this, accept());
 }
 
-void QVLCProgressDialog::destroy (void *priv)
+void LoginDialogWrapper::accept()
 {
-    QVLCProgressDialog *self = static_cast<QVLCProgressDialog *>(priv);
-
-    emit self->released ();
+    if (p_id != NULL)
+    {
+        vlc_dialog_id_post_login(p_id, qtu(userLine->text ()),
+                                 qtu(passLine->text ()),
+                                 checkbox != NULL ? checkbox->isChecked () : false);
+        p_id = NULL;
+        if (checkbox != NULL)
+            getSettings()->setValue ("store_password", checkbox->isChecked ());
+    }
 }
 
-void QVLCProgressDialog::saveCancel (void)
+QuestionDialogWrapper::QuestionDialogWrapper(DialogHandler *p_handler,
+                                             intf_thread_t *p_intf,
+                                             vlc_dialog_id *p_id,
+                                             QMessageBox *p_box,
+                                             QAbstractButton *action1,
+                                             QAbstractButton *action2)
+    : DialogWrapper(p_handler, p_intf, p_id, p_box)
+    , action1(action1)
+    , action2(action2)
 {
-    QMutexLocker locker (&cancel_mutex);
-    cancelled = true;
+    CONNECT(p_box, buttonClicked(QAbstractButton *),
+            this, buttonClicked(QAbstractButton *));
 }
 
-void DialogHandler::startProgressBar (void *value)
+void QuestionDialogWrapper::buttonClicked(QAbstractButton *button)
 {
-    dialog_progress_bar_t *data = (dialog_progress_bar_t *)value;
-    QWidget *dlg = new QVLCProgressDialog (this, data);
+    if (p_id != NULL)
+    {
+        if (button == action1)
+            vlc_dialog_id_post_action(p_id, 1);
+        else if (button == action2)
+            vlc_dialog_id_post_action(p_id, 2);
+        else
+            vlc_dialog_id_dismiss(p_id);
+        p_id = NULL;
+    }
+}
 
-    QTimer::singleShot( 1500, dlg, SLOT( show() ) );
-//    dlg->show ();
+ProgressDialogWrapper::ProgressDialogWrapper(DialogHandler *p_handler,
+                                             intf_thread_t *p_intf,
+                                             vlc_dialog_id *p_id,
+                                             QProgressDialog *p_progress,
+                                             bool b_indeterminate)
+    : DialogWrapper(p_handler, p_intf, p_id, p_progress)
+    , b_indeterminate(b_indeterminate)
+{
+    CONNECT(p_progress, canceled(void), this, finish(void));
 }
 
-void DialogHandler::stopProgressBar (QWidget *dlg)
+void ProgressDialogWrapper::updateProgress(float f_position, const QString &text)
 {
-    delete dlg;
+    if (!b_indeterminate)
+    {
+        QProgressDialog *progress = static_cast<QProgressDialog *>(p_dialog);
+        progress->setLabelText(text);
+        progress->setValue(f_position * 1000);
+    }
 }
diff --git a/modules/gui/qt4/dialogs/external.hpp b/modules/gui/qt4/dialogs/external.hpp
index 1a8fe68..f955f08 100644
--- a/modules/gui/qt4/dialogs/external.hpp
+++ b/modules/gui/qt4/dialogs/external.hpp
@@ -26,65 +26,125 @@
 #endif
 
 #include <QObject>
+#include <QDialog>
+#include <QMap>
 #include <vlc_common.h>
+#include <vlc_dialog.h>
 #include "adapters/variables.hpp"
 
 struct intf_thread_t;
 class QProgressDialog;
+class DialogWrapper;
 
 class DialogHandler : public QObject
 {
     Q_OBJECT
 
-    friend class QVLCProgressDialog;
-
 public:
     DialogHandler (intf_thread_t *, QObject *parent);
-    virtual ~DialogHandler (void);
+    virtual ~DialogHandler();
+    void removeDialogId(vlc_dialog_id *p_id);
 
-private:
-    intf_thread_t *p_intf;
-    static int error (vlc_object_t *, const char *, vlc_value_t, vlc_value_t,
-                      void *);
-    QVLCPointer critical;
-    QVLCPointer login;
-    QVLCPointer question;
-    QVLCPointer progressBar;
 signals:
-    void error (const QString&, const QString&);
+    void errorDisplayed(const QString &title, const QString &text);
+    void loginDisplayed(vlc_dialog_id *p_id, const QString &title,
+                        const QString &text, const QString &defaultUsername,
+                        bool b_ask_store);
+    void questionDisplayed(vlc_dialog_id *p_id, const QString &title,
+                           const QString &text, int i_type,
+                           const QString &cancel, const QString &action1,
+                           const QString &action2);
+    void progressDisplayed(vlc_dialog_id *p_id, const QString &title,
+                           const QString &text, bool b_indeterminate,
+                           float f_position, const QString &cancel);
+    void cancelled(vlc_dialog_id *p_id);
+    void progressUpdated(vlc_dialog_id *p_id, float f_value, const QString &text);
 
 private slots:
-    void displayError (const QString&, const QString&);
-    void displayCritical (void *);
-    void requestLogin (void *);
-    void requestAnswer (void *);
-    void startProgressBar (void *);
-    void stopProgressBar (QWidget *);
+    void displayError(const QString &title, const QString &text);
+    void displayLogin(vlc_dialog_id *p_id, const QString &title,
+                      const QString &text, const QString &defaultUsername,
+                      bool b_ask_store);
+    void displayQuestion(vlc_dialog_id *p_id, const QString &title,
+                         const QString &text, int i_type,
+                         const QString &cancel, const QString &action1,
+                         const QString &action2);
+    void displayProgress(vlc_dialog_id *p_id, const QString &title,
+                         const QString &text, bool b_indeterminate,
+                         float f_position, const QString &cancel);
+    void cancel(vlc_dialog_id *p_id);
+    void updateProgress(vlc_dialog_id *p_id, float f_value, const QString &text);
+
+private:
+    intf_thread_t *p_intf;
+
+    static bool displayCb(vlc_dialog_id *, vlc_dialog *, void *);
+    static void cancelCb(vlc_dialog_id *, void *);
+    static void updateProgressCb(vlc_dialog_id *, float, const char *, void *);
 };
 
-/* Put here instead of .cpp because of MOC */
-#include <QProgressDialog>
+class DialogWrapper : public QObject
+{
+    Q_OBJECT
+
+    friend class DialogHandler;
+public:
+    DialogWrapper(DialogHandler *p_handler, intf_thread_t *p_intf,
+                 vlc_dialog_id *p_id, QDialog *p_dialog);
+    virtual ~DialogWrapper();
+protected slots:
+    virtual void finish(int result = QDialog::Rejected);
+protected:
+    DialogHandler *p_handler;
+    intf_thread_t *p_intf;
+    vlc_dialog_id *p_id;
+    QDialog *p_dialog;
+};
 
-class QVLCProgressDialog : public QProgressDialog
+class QLineEdit;
+class QCheckBox;
+class LoginDialogWrapper : public DialogWrapper
 {
     Q_OBJECT
 public:
-    QVLCProgressDialog (DialogHandler *parent,
-                        struct dialog_progress_bar_t *);
+    LoginDialogWrapper(DialogHandler *p_handler, intf_thread_t *p_intf,
+                       vlc_dialog_id *p_id, QDialog *p_dialog,
+                       QLineEdit *userLine, QLineEdit *passLine,
+                       QCheckBox *checkbox);
+private slots:
+    virtual void accept();
 private:
-    DialogHandler *handler;
-    bool cancelled;
+    QLineEdit *userLine;
+    QLineEdit *passLine;
+    QCheckBox *checkbox;
+};
 
-    static void update (void *, const char *, float);
-    static bool check (void *);
-    static void destroy (void *);
+class QAbstractButton;
+class QMessageBox;
+class QuestionDialogWrapper : public DialogWrapper
+{
+    Q_OBJECT
+public:
+    QuestionDialogWrapper(DialogHandler *p_handler, intf_thread_t *p_intf,
+                          vlc_dialog_id *p_id, QMessageBox *p_box,
+                          QAbstractButton *action1, QAbstractButton *action2);
 private slots:
-    void saveCancel (void);
+    virtual void buttonClicked(QAbstractButton *);
+private:
+    QAbstractButton *action1;
+    QAbstractButton *action2;
+};
 
-signals:
-    void progressed (int);
-    void described (const QString&);
-    void released (void);
+class ProgressDialogWrapper : public DialogWrapper
+{
+    Q_OBJECT
+public:
+    ProgressDialogWrapper(DialogHandler *p_handler, intf_thread_t *p_intf,
+                          vlc_dialog_id *p_id, QProgressDialog  *p_progress,
+                          bool b_indeterminate);
+    void updateProgress(float f_position, const QString &text);
+private:
+    bool b_indeterminate;
 };
 
 #endif
diff --git a/modules/lua/extension.c b/modules/lua/extension.c
index 9546e4c..da75e40 100644
--- a/modules/lua/extension.c
+++ b/modules/lua/extension.c
@@ -964,10 +964,10 @@ int lua_ExecuteFunctionVa( extensions_manager_t *p_mgr, extension_t *p_ext,
 
     // Reset watch timer and timestamp
     vlc_mutex_lock( &p_ext->p_sys->command_lock );
-    if( p_ext->p_sys->progress )
+    if( p_ext->p_sys->p_progress_id != NULL )
     {
-        dialog_ProgressDestroy( p_ext->p_sys->progress );
-        p_ext->p_sys->progress = NULL;
+        vlc_dialog_id_release( p_ext->p_sys->p_progress_id );
+        p_ext->p_sys->p_progress_id = NULL;
     }
     vlc_timer_schedule( p_ext->p_sys->timer, false, 0, 0 );
     vlc_mutex_unlock( &p_ext->p_sys->command_lock );
@@ -1021,10 +1021,10 @@ int lua_ExtensionTriggerMenu( extensions_manager_t *p_mgr,
 
     // Reset watch timer and timestamp
     vlc_mutex_lock( &p_ext->p_sys->command_lock );
-    if( p_ext->p_sys->progress )
+    if( p_ext->p_sys->p_progress_id != NULL )
     {
-        dialog_ProgressDestroy( p_ext->p_sys->progress );
-        p_ext->p_sys->progress = NULL;
+        vlc_dialog_id_release( p_ext->p_sys->p_progress_id );
+        p_ext->p_sys->p_progress_id = NULL;
     }
     vlc_timer_schedule( p_ext->p_sys->timer, false, 0, 0 );
     vlc_mutex_unlock( &p_ext->p_sys->command_lock );
@@ -1106,10 +1106,10 @@ int vlclua_extension_keep_alive( lua_State *L )
     extension_t *p_ext = vlclua_extension_get( L );
 
     vlc_mutex_lock( &p_ext->p_sys->command_lock );
-    if( p_ext->p_sys->progress )
+    if( p_ext->p_sys->p_progress_id != NULL )
     {
-        dialog_ProgressDestroy( p_ext->p_sys->progress );
-        p_ext->p_sys->progress = NULL;
+        vlc_dialog_id_release( p_ext->p_sys->p_progress_id );
+        p_ext->p_sys->p_progress_id = NULL;
     }
     vlc_timer_schedule( p_ext->p_sys->timer, false, WATCH_TIMER_PERIOD, 0 );
     vlc_mutex_unlock( &p_ext->p_sys->command_lock );
@@ -1211,14 +1211,6 @@ static void WatchTimerCallback( void *data )
     extension_t *p_ext = data;
     extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
 
-    char *message;
-    if( asprintf( &message, _( "Extension '%s' does not respond.\n"
-                               "Do you want to kill it now? " ),
-                  p_ext->psz_title ) == -1 )
-    {
-        return;
-    }
-
     vlc_mutex_lock( &p_ext->p_sys->command_lock );
 
     for( struct command_t *cmd = p_ext->p_sys->command;
@@ -1226,30 +1218,39 @@ static void WatchTimerCallback( void *data )
          cmd = cmd->next )
         if( cmd->i_command == CMD_DEACTIVATE )
         {   /* We have a pending Deactivate command... */
-            if( p_ext->p_sys->progress )
+            if( p_ext->p_sys->p_progress_id != NULL )
             {
-                dialog_ProgressDestroy( p_ext->p_sys->progress );
-                p_ext->p_sys->progress = NULL;
+                vlc_dialog_id_release( p_ext->p_sys->p_progress_id );
+                p_ext->p_sys->p_progress_id = NULL;
             }
             vlc_mutex_unlock( &p_ext->p_sys->command_lock );
             KillExtension( p_mgr, p_ext );
             return;
         }
 
-    if( !p_ext->p_sys->progress )
+    if( p_ext->p_sys->p_progress_id == NULL )
     {
-        p_ext->p_sys->progress =
-                dialog_ProgressCreate( p_mgr, _( "Extension not responding!" ),
-                                       message,
-                                       _( "Yes" ) );
+        p_ext->p_sys->p_progress_id =
+            vlc_dialog_display_progress( p_mgr, true, 0.0,
+                                         _( "Yes" ),
+                                         _( "Extension not responding!" ),
+                                         _( "Extension '%s' does not respond.\n"
+                                         "Do you want to kill it now? " ),
+                                         p_ext->psz_title );
+        if( p_ext->p_sys->p_progress_id == NULL )
+        {
+            vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+            KillExtension( p_mgr, p_ext );
+            return;
+        }
         vlc_timer_schedule( p_ext->p_sys->timer, false, 100000, 0 );
     }
     else
     {
-        if( dialog_ProgressCancelled( p_ext->p_sys->progress ) )
+        if( vlc_dialog_id_is_cancelled( p_ext->p_sys->p_progress_id ) )
         {
-            dialog_ProgressDestroy( p_ext->p_sys->progress );
-            p_ext->p_sys->progress = NULL;
+            vlc_dialog_id_release( p_ext->p_sys->p_progress_id );
+            p_ext->p_sys->p_progress_id = NULL;
             vlc_mutex_unlock( &p_ext->p_sys->command_lock );
             KillExtension( p_mgr, p_ext );
             return;
diff --git a/modules/lua/extension.h b/modules/lua/extension.h
index 69f1705..1626334 100644
--- a/modules/lua/extension.h
+++ b/modules/lua/extension.h
@@ -91,7 +91,7 @@ struct extension_sys_t
     } *command;
 
     // The two following booleans are protected by command_lock
-    dialog_progress_bar_t *progress;
+    vlc_dialog_id *p_progress_id;
     vlc_timer_t timer; ///< This timer makes sure Lua never gets stuck >5s
 
     bool b_exiting;
diff --git a/modules/lua/extension_thread.c b/modules/lua/extension_thread.c
index 17d4276..61e88e7 100644
--- a/modules/lua/extension_thread.c
+++ b/modules/lua/extension_thread.c
@@ -149,11 +149,11 @@ int Deactivate( extensions_manager_t *p_mgr, extension_t *p_ext )
         return VLC_EGENERIC;
     }
 
-    if( p_ext->p_sys->progress )
+    if( p_ext->p_sys->p_progress_id != NULL )
     {
         // Extension is stuck, kill it now
-        dialog_ProgressDestroy( p_ext->p_sys->progress );
-        p_ext->p_sys->progress = NULL;
+        vlc_dialog_id_release( p_ext->p_sys->p_progress_id );
+        p_ext->p_sys->p_progress_id = NULL;
         vlc_mutex_unlock( &p_ext->p_sys->command_lock );
         KillExtension( p_mgr, p_ext );
         return VLC_SUCCESS;
diff --git a/modules/misc/gnutls.c b/modules/misc/gnutls.c
index 43ef396..692f901 100644
--- a/modules/misc/gnutls.c
+++ b/modules/misc/gnutls.c
@@ -490,13 +490,13 @@ error:
             goto error;
     }
 
-    if (dialog_Question(creds, _("Insecure site"),
-        _("You attempted to reach %s. %s\n"
-          "This problem may be stem from an attempt to breach your security, "
-          "compromise your privacy, or a configuration error.\n\n"
-          "If in doubt, abort now.\n"),
-                        _("Abort"), _("View certificate"), NULL,
-                        vlc_gettext(msg), host) != 2)
+    if (vlc_dialog_wait_question(creds, VLC_DIALOG_QUESTION_NORMAL,
+            _("Abort"), _("View certificate"), NULL,
+            _("Insecure site"), 
+            _("You attempted to reach %s. %s\n"
+            "This problem may be stem from an attempt to breach your security, "
+            "compromise your privacy, or a configuration error.\n\n"
+            "If in doubt, abort now.\n"), host, vlc_gettext(msg)) != 1)
         goto error;
 
     gnutls_x509_crt_t cert;
@@ -511,20 +511,20 @@ error:
     }
     gnutls_x509_crt_deinit (cert);
 
-    val = dialog_Question(creds, _("Insecure site"),
-         _("This is the certificate presented by %s:\n%s\n\n"
-           "If in doubt, abort now.\n"),
-                          _("Abort"), _("Accept 24 hours"),
-                          _("Accept permanently"), host, desc.data);
+    val = vlc_dialog_wait_question(creds, VLC_DIALOG_QUESTION_NORMAL,
+            _("Abort"), _("Accept 24 hours"), _("Accept permanently"),
+            _("Insecure site"),
+            _("This is the certificate presented by %s:\n%s\n\n"
+            "If in doubt, abort now.\n"), host, desc.data);
     gnutls_free (desc.data);
 
     time_t expiry = 0;
     switch (val)
     {
-        case 2:
+        case 1:
             time (&expiry);
             expiry += 24 * 60 * 60;
-        case 3:
+        case 2:
             val = gnutls_store_pubkey (NULL, NULL, host, service,
                                        GNUTLS_CRT_X509, datum, expiry, 0);
             if (val)
diff --git a/modules/misc/securetransport.c b/modules/misc/securetransport.c
index a313ce2..8e9afc4 100644
--- a/modules/misc/securetransport.c
+++ b/modules/misc/securetransport.c
@@ -330,10 +330,12 @@ static int st_validateServerCertificate (vlc_tls_t *session, const char *hostnam
              "This problem may be caused by a configuration error "
              "or an attempt to breach your security or your privacy.\n\n"
              "If in doubt, abort now.\n");
-    int answer = dialog_Question(session->obj, _("Insecure site"), vlc_gettext (msg),
-                                  _("Abort"), _("Accept certificate temporarily"), NULL, hostname);
-
-    if (answer == 2) {
+    int answer = vlc_dialog_wait_question(session->obj,
+                                          VLC_DIALOG_QUESTION_NORMAL, _("Abort"),
+                                          _("Accept certificate temporarily"),
+                                          NULL, _("Insecure site"),
+                                          vlc_gettext (msg), hostname);
+    if (answer == 1) {
         msg_Warn(session->obj, "Proceeding despite of failed certificate validation");
 
         /* save leaf certificate in whitelist */
diff --git a/modules/text_renderer/freetype/fonts/fontconfig.c b/modules/text_renderer/freetype/fonts/fontconfig.c
index 2c1e5f0..1165b34 100644
--- a/modules/text_renderer/freetype/fonts/fontconfig.c
+++ b/modules/text_renderer/freetype/fonts/fontconfig.c
@@ -54,26 +54,24 @@ int FontConfig_Prepare( filter_t *p_filter )
 #endif
 
 #if defined( _WIN32 )
+    int i_ret;
+    unsigned int i_dialog_id = 0;
     dialog_progress_bar_t *p_dialog = NULL;
     FcConfig *fcConfig = FcInitLoadConfig();
 
-    p_dialog = dialog_ProgressCreate( p_filter,
-            _("Building font cache"),
-            _("Please wait while your font cache is rebuilt.\n"
-                "This should take less than a few minutes."), NULL );
+    i_ret =
+        vlc_dialog_display_progress( p_filter, true, 0.0, NULL,
+                                     _("Building font cache"),
+                                     _("Please wait while your font cache is rebuilt.\n"
+                                     "This should take less than a few minutes.") );
 
-/*    if( p_dialog )
-        dialog_ProgressSet( p_dialog, NULL, 0.5 ); */
+    i_dialog_id = i_ret > 0 ? i_ret : 0;
 
     if( FcConfigBuildFonts( fcConfig ) == FcFalse )
         return VLC_ENOMEM;
 
-    if( p_dialog )
-    {
-//        dialog_ProgressSet( p_dialog, NULL, 1.0 );
-        dialog_ProgressDestroy( p_dialog );
-        p_dialog = NULL;
-    }
+    if( i_dialog_id != 0 )
+        vlc_dialog_cancel( p_filter, i_dialog_id );
 #endif
     t2 = mdate();
     msg_Dbg( p_filter, "Took %ld microseconds", (long)((t2 - t1)) );
diff --git a/src/interface/dialog.c b/src/interface/dialog.c
index 94450db..6681f39 100644
--- a/src/interface/dialog.c
+++ b/src/interface/dialog.c
@@ -27,277 +27,741 @@
 # include "config.h"
 #endif
 
-#include <stdarg.h>
-
 #include <vlc_common.h>
 #include <vlc_dialog.h>
+#include <vlc_interrupt.h>
 #include <vlc_extensions.h>
 #include <assert.h>
 #include "libvlc.h"
 
-static vlc_mutex_t provider_lock = VLC_STATIC_MUTEX;
+struct vlc_dialog_provider
+{
+    vlc_mutex_t     lock;
+    vlc_array_t     dialog_array;
+    vlc_dialog_cbs  cbs;
+    void *          p_cbs_data;
+};
 
-#undef dialog_Register
-/**
- * Registers an object as the dialog provider.
- * It is assumed that the appropriate variable callbacks are already
- * registered.
- */
-int dialog_Register (vlc_object_t *obj)
+struct dialog_answer
+{
+    vlc_dialog_type i_type;
+    union
+    {
+        struct
+        {
+            char *psz_username;
+            char *psz_password;
+            bool b_store;
+        } login;
+        struct
+        {
+            int i_action;
+        } question;
+    } u;
+};
+
+struct vlc_dialog_id
 {
-    libvlc_priv_t *priv = libvlc_priv (obj->p_libvlc);
-    int ret = VLC_EGENERIC;
+    vlc_mutex_t             lock;
+    vlc_cond_t              wait;
+    vlc_dialog_type         i_type;
+    vlc_dialog_provider *   p_provider;
+    void *                  p_context;
+    int                     i_refcount;
+    bool                    b_cancelled;
+    bool                    b_answered;
+    bool                    b_progress_indeterminate;
+    char *                  psz_progress_text;
+    struct dialog_answer    answer;
+};
+
+static inline vlc_dialog_provider *
+get_dialog_provider(vlc_object_t *p_obj, bool b_check_interact)
+{
+    if (b_check_interact && p_obj->i_flags & OBJECT_FLAGS_NOINTERACT)
+        return NULL;
+    return libvlc_priv(p_obj->p_libvlc)->p_dialog_provider;
+}
 
-    vlc_mutex_lock (&provider_lock);
-    if (priv->p_dialog_provider == NULL)
-    {   /* Since the object is responsible for unregistering itself before
-         * it terminates, at reference is not needed. */
-        priv->p_dialog_provider = obj;
-        ret = VLC_SUCCESS;
+static void
+dialog_id_release(vlc_dialog_id *p_id)
+{
+    if (p_id->answer.i_type == VLC_DIALOG_LOGIN)
+    {
+        free(p_id->answer.u.login.psz_username);
+        free(p_id->answer.u.login.psz_password);
     }
-    vlc_mutex_unlock (&provider_lock);
-    return ret;
+    free(p_id->psz_progress_text);
+    vlc_mutex_destroy(&p_id->lock);
+    vlc_cond_destroy(&p_id->wait);
+    free(p_id);
 }
 
-#undef dialog_Unregister
-/**
- * Unregisters the dialog provider.
- * Note that unless you have unregistered the callbacks already, the provider
- * might still be in use by other threads. Also, you need to cancel all
- * pending dialogs yourself.
- */
-int dialog_Unregister (vlc_object_t *obj)
+#undef dialog_ExtensionUpdate
+int dialog_ExtensionUpdate (vlc_object_t *obj, extension_dialog_t *dialog)
 {
-    libvlc_priv_t *priv = libvlc_priv (obj->p_libvlc);
-    int ret = VLC_EGENERIC;
+    assert (obj);
+    assert (dialog);
 
-    vlc_mutex_lock (&provider_lock);
-    if (priv->p_dialog_provider == obj)
+    vlc_object_t *dp = NULL;//dialog_GetProvider(obj);
+    if (!dp)
     {
-        priv->p_dialog_provider = NULL;
-        ret = VLC_SUCCESS;
+        msg_Warn (obj, "Dialog provider is not set, can't update dialog '%s'",
+                  dialog->psz_title);
+        return VLC_EGENERIC;
     }
-    vlc_mutex_unlock (&provider_lock);
+
+    // Signaling the dialog provider
+    int ret = var_SetAddress (dp, "dialog-extension", dialog);
+
+    vlc_object_release (dp);
     return ret;
 }
 
-static vlc_object_t *dialog_GetProvider (vlc_object_t *obj)
+vlc_dialog_provider *
+vlc_dialog_provider_new(void)
 {
-    libvlc_priv_t *priv = libvlc_priv (obj->p_libvlc);
-    vlc_object_t *provider;
+    vlc_dialog_provider *p_provider = malloc(sizeof(*p_provider));
+    if( p_provider == NULL )
+        return NULL;
+
+    vlc_mutex_init(&p_provider->lock);
+    vlc_array_init(&p_provider->dialog_array);
+
+    memset(&p_provider->cbs, 0, sizeof(p_provider->cbs));
+    p_provider->p_cbs_data = NULL;
 
-    vlc_mutex_lock (&provider_lock);
-    if ((provider = priv->p_dialog_provider) != NULL)
-        vlc_object_hold (provider);
-    vlc_mutex_unlock (&provider_lock);
-    return provider;
+    return p_provider;
 }
 
-/**
- * Sends an error message through the user interface (if any).
- * @param obj the VLC object emitting the error
- * @param modal whether to wait for user to acknowledge the error
- *              before returning control to the caller
- * @param title title of the error dialog
- * @param fmt format string for the error message
- * @param ap parameters list for the formatted error message
- */
-void dialog_VFatal (vlc_object_t *obj, bool modal, const char *title,
-                    const char *fmt, va_list ap)
+static int
+dialog_get_idx_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id)
 {
-    char *text;
+    for (int i = 0; i < vlc_array_count(&p_provider->dialog_array); ++i)
+    {
+        if (p_id == vlc_array_item_at_index(&p_provider->dialog_array, i))
+            return i;
+    }
+    return -1;
+}
 
-    if (obj->i_flags & OBJECT_FLAGS_NOINTERACT)
+static void
+dialog_cancel_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id)
+{
+    vlc_mutex_lock(&p_id->lock);
+    if (p_id->b_cancelled || p_id->b_answered)
+    {
+        vlc_mutex_unlock(&p_id->lock);
         return;
+    }
+    p_id->b_cancelled = true;
+    vlc_mutex_unlock(&p_id->lock);
+
+    p_provider->cbs.pf_cancel(p_id, p_provider->p_cbs_data);
+}
+
+static void
+dialog_remove_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id,
+                     bool b_force_release)
+{
+    int i_array_idx = dialog_get_idx_locked(p_provider, p_id);
+    assert(i_array_idx >= 0);
 
-    vlc_object_t *provider = dialog_GetProvider (obj);
-    if (provider == NULL)
+    vlc_array_remove(&p_provider->dialog_array, i_array_idx);
+
+    vlc_mutex_lock(&p_id->lock);
+    p_id->i_refcount--;
+    if (p_id->i_refcount == 0 || b_force_release)
     {
-        msg_Err (obj, "%s", title);
-        msg_GenericVa (obj, VLC_MSG_ERR, fmt, ap);
-        return;
+        vlc_mutex_unlock(&p_id->lock);
+        dialog_id_release(p_id);
     }
+    else
+        vlc_mutex_unlock(&p_id->lock);
+}
 
-    if (vasprintf (&text, fmt, ap) != -1)
+static void
+dialog_clear_all_locked(vlc_dialog_provider *p_provider)
+{
+    for (int i = 0; i < vlc_array_count(&p_provider->dialog_array); ++i)
     {
-        dialog_fatal_t dialog = { title, text, };
-        var_SetAddress (provider,
-                        modal ? "dialog-critical" : "dialog-error", &dialog);
-        free (text);
+        vlc_dialog_id *p_id =
+            vlc_array_item_at_index(&p_provider->dialog_array, i);
+        dialog_cancel_locked(p_provider, p_id);
     }
-    vlc_object_release (provider);
+    vlc_array_clear(&p_provider->dialog_array);
 }
 
-#undef dialog_vaLogin
-void dialog_vaLogin (vlc_object_t *obj, const char *default_username,
-                   char **username, char **password, bool *store,
-                   const char *title, const char *fmt, va_list ap)
+void
+vlc_dialog_provider_release(vlc_dialog_provider *p_provider)
 {
-    assert ((username != NULL) && (password != NULL));
+    assert(p_provider != NULL);
 
-    *username = *password = NULL;
-    if (obj->i_flags & OBJECT_FLAGS_NOINTERACT)
-        return;
+    vlc_mutex_lock(&p_provider->lock);
+    dialog_clear_all_locked(p_provider);
+    vlc_mutex_unlock(&p_provider->lock);
 
-    vlc_object_t *provider = dialog_GetProvider (obj);
-    if (provider == NULL)
-        return;
+    vlc_mutex_destroy(&p_provider->lock);
+    free(p_provider);
+}
+
+#undef vlc_dialog_provider_set_callbacks
+void
+vlc_dialog_provider_set_callbacks(vlc_object_t *p_obj,
+                                  vlc_dialog_cbs *p_cbs, void *p_data)
+{
+    assert(p_obj != NULL);
+    vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
+    assert(p_provider != NULL);
 
-    char *text;
+    vlc_mutex_lock(&p_provider->lock);
+    dialog_clear_all_locked(p_provider);
 
-    if (vasprintf (&text, fmt, ap) != -1)
+    if (p_cbs == NULL)
+    {
+        memset(&p_provider->cbs, 0, sizeof(p_provider->cbs));
+        p_provider->p_cbs_data = NULL;
+    }
+    else
     {
-        dialog_login_t dialog = { title, text, default_username, username,
-                                  password, store };
-        var_SetAddress (provider, "dialog-login", &dialog);
-        free (text);
+        assert(p_cbs->pf_display != NULL && p_cbs->pf_cancel != NULL);
+        p_provider->cbs = *p_cbs;
+        p_provider->p_cbs_data = p_data;
     }
-    vlc_object_release (provider);
+    vlc_mutex_unlock(&p_provider->lock);
 }
 
-#undef dialog_Login
-/**
- * Requests a username and password through the user interface.
- * @param obj the VLC object requesting credential information
- * @param username a pointer to the specified username [OUT]
- * @param password a pointer to the specified password [OUT]
- * @param title title for the dialog
- * @param fmt format string for the message in the dialog
- * @return Nothing. If a user name resp. a password was specified,
- * it will be returned as a heap-allocated character array
- * into the username resp password pointer. Those must be freed with free().
- * Otherwise *username resp *password will be NULL.
- */
-void dialog_Login (vlc_object_t *obj, const char *default_username,
-                   char **username, char **password,
-                   bool *store, const char *title, const char *fmt, ...)
+static void
+dialog_wait_interrupted(void *p_data)
+{
+    vlc_dialog_id *p_id = p_data;
+    vlc_dialog_provider *p_provider = p_id->p_provider;
+
+    vlc_mutex_lock(&p_provider->lock);
+    dialog_cancel_locked(p_provider, p_id);
+    vlc_mutex_unlock(&p_provider->lock);
+
+    vlc_mutex_lock(&p_id->lock);
+    vlc_cond_signal(&p_id->wait);
+    vlc_mutex_unlock(&p_id->lock);
+}
+
+static int
+dialog_wait(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id,
+            vlc_dialog_type i_type, struct dialog_answer *p_answer)
+{
+    vlc_interrupt_register(dialog_wait_interrupted, p_id);
+
+    vlc_mutex_lock(&p_id->lock);
+    /* Wait for the dialog to be dismissed, interrupted or answered */
+    while (!p_id->b_cancelled && !p_id->b_answered)
+        vlc_cond_wait(&p_id->wait, &p_id->lock);
+
+    int i_ret;
+    if (p_id->b_cancelled)
+        i_ret = 0;
+    else if (p_id->answer.i_type != i_type)
+        i_ret = VLC_EGENERIC;
+    else
+    {
+        i_ret = 1;
+        memcpy(p_answer, &p_id->answer, sizeof(p_id->answer));
+        memset(&p_id->answer, 0, sizeof(p_id->answer));
+    }
+
+    vlc_mutex_unlock(&p_id->lock);
+    vlc_interrupt_unregister();
+
+    vlc_mutex_lock(&p_provider->lock);
+    dialog_remove_locked(p_provider, p_id, false);
+    vlc_mutex_unlock(&p_provider->lock);
+    return i_ret;
+}
+
+static int
+dialog_display(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
+               vlc_dialog *p_dialog)
+{
+    vlc_dialog_id *p_id = NULL;
+
+    vlc_mutex_lock(&p_provider->lock);
+    if (p_provider->cbs.pf_display == NULL)
+    {
+        vlc_mutex_unlock(&p_provider->lock);
+        return VLC_EGENERIC;
+    }
+
+    if (pp_id != NULL)
+    {
+        p_id = calloc(1, sizeof(*p_id));
+        vlc_mutex_init(&p_id->lock);
+        vlc_cond_init(&p_id->wait);
+        if (p_id == NULL)
+        {
+            vlc_mutex_unlock(&p_provider->lock);
+            return VLC_ENOMEM;
+        }
+
+        p_id->p_provider = p_provider;
+        p_id->i_type = p_dialog->i_type;
+        p_id->i_refcount = 2; /* provider and callbacks */
+
+        vlc_array_append(&p_provider->dialog_array, p_id);
+    }
+
+    if (!p_provider->cbs.pf_display(p_id, p_dialog, p_provider->p_cbs_data)
+     && p_id != NULL)
+    {
+        dialog_remove_locked(p_provider, p_id, true);
+        p_id = NULL;
+    }
+    if (pp_id != NULL)
+        *pp_id = p_id;
+
+    vlc_mutex_unlock(&p_provider->lock);
+
+    return VLC_SUCCESS;
+}
+
+static int
+dialog_display_error_va(vlc_dialog_provider *p_provider, const char *psz_title,
+                        const char *psz_fmt, va_list ap)
 {
+    char *psz_text;
+    if (vasprintf(&psz_text, psz_fmt, ap) == -1)
+        return VLC_ENOMEM;
+
+    vlc_dialog dialog = {
+        .i_type = VLC_DIALOG_ERROR,
+        .psz_title = psz_title,
+        .psz_text = psz_text,
+    };
+
+    int i_ret = dialog_display(p_provider, NULL, &dialog);
+    free(psz_text);
+    return i_ret;
+}
+
+int
+vlc_dialog_display_error_va(vlc_object_t *p_obj, const char *psz_title,
+                            const char *psz_fmt, va_list ap)
+{
+    assert(p_obj != NULL && psz_title != NULL && psz_fmt != NULL);
+    vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
+    if (p_provider == NULL)
+        return VLC_EGENERIC;
+
+    return dialog_display_error_va(p_provider, psz_title, psz_fmt, ap);
+}
+
+
+#undef vlc_dialog_display_error
+int
+vlc_dialog_display_error(vlc_object_t *p_obj, const char *psz_title,
+                         const char *psz_fmt, ...)
+{
+    assert(psz_fmt != NULL);
     va_list ap;
-    va_start (ap, fmt);
-    dialog_vaLogin (obj, default_username, username, password, store,
-                    title, fmt, ap);
-    va_end (ap);
+    va_start(ap, psz_fmt);
+    int i_ret = vlc_dialog_display_error_va(p_obj, psz_title, psz_fmt, ap);
+    va_end(ap);
+    return i_ret;
 }
 
-#undef dialog_Question
-/**
- * Asks a total (Yes/No/Cancel) question through the user interface.
- * @param obj VLC object emitting the question
- * @param title dialog box title
- * @param fmt format string for the dialog box text
- * @param yes first choice/button text
- * @param no second choice/button text
- * @param cancel third answer/button text, or NULL if no third option
- * @return 0 if the user could not answer the question (e.g. there is no UI),
- * 1, 2 resp. 3 if the user pressed the first, second resp. third button.
- */
-int dialog_Question (vlc_object_t *obj, const char *title, const char *fmt,
-                     const char *yes, const char *no, const char *cancel, ...)
+static int
+dialog_display_login_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
+                        const char *psz_default_username, bool b_ask_store,
+                        const char *psz_title, const char *psz_fmt, va_list ap)
 {
-    if (obj->i_flags & OBJECT_FLAGS_NOINTERACT)
-        return 0;
+    char *psz_text;
+    if (vasprintf(&psz_text, psz_fmt, ap) == -1)
+        return VLC_ENOMEM;
+
+    vlc_dialog dialog = {
+        .i_type = VLC_DIALOG_LOGIN,
+        .psz_title = psz_title,
+        .psz_text = psz_text,
+        .u.login = {
+            .psz_default_username = psz_default_username,
+            .b_ask_store = b_ask_store,
+        }
+    };
+
+    int i_ret = dialog_display(p_provider, pp_id, &dialog);
+    free(psz_text);
+    return i_ret;
+}
+
+int
+vlc_dialog_wait_login_va(vlc_object_t *p_obj,  char **ppsz_username,
+                         char **ppsz_password, bool *p_store,
+                         const char *psz_default_username,
+                         const char *psz_title, const char *psz_fmt, va_list ap)
+{
+    assert(p_obj != NULL && ppsz_username != NULL && ppsz_password != NULL
+        && psz_fmt != NULL && psz_title != NULL);
+
+    vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
+    if (p_provider == NULL)
+        return VLC_EGENERIC;
+
+    vlc_dialog_id *p_id;
+    int i_ret = dialog_display_login_va(p_provider, &p_id, psz_default_username,
+                                        p_store != NULL, psz_title, psz_fmt, ap);
+    if (i_ret < 0 || p_id == NULL)
+        return i_ret;
+
+    struct dialog_answer answer;
+    i_ret = dialog_wait(p_provider, p_id, VLC_DIALOG_LOGIN, &answer);
+    if (i_ret <= 0)
+        return i_ret;
+
+    *ppsz_username = answer.u.login.psz_username;
+    *ppsz_password = answer.u.login.psz_password;
+    if (p_store != NULL)
+        *p_store = answer.u.login.b_store;
+
+    return 1;
+}
+
+#undef vlc_dialog_wait_login
+int
+vlc_dialog_wait_login(vlc_object_t *p_obj,  char **ppsz_username,
+                      char **ppsz_password, bool *p_store,
+                      const char *psz_default_username, const char *psz_title,
+                      const char *psz_fmt, ...)
+{
+    assert(psz_fmt != NULL);
+    va_list ap;
+    va_start(ap, psz_fmt);
+    int i_ret = vlc_dialog_wait_login_va(p_obj, ppsz_username, ppsz_password,
+                                         p_store,psz_default_username,
+                                         psz_title, psz_fmt, ap);
+    va_end(ap);
+    return i_ret;
+}
+
+static int
+dialog_display_question_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
+                           vlc_dialog_question_type i_type,
+                           const char *psz_cancel, const char *psz_action1,
+                           const char *psz_action2, const char *psz_title,
+                           const char *psz_fmt, va_list ap)
+{
+    char *psz_text;
+    if (vasprintf(&psz_text, psz_fmt, ap) == -1)
+        return VLC_ENOMEM;
+
+    vlc_dialog dialog = {
+        .i_type = VLC_DIALOG_QUESTION,
+        .psz_title = psz_title,
+        .psz_text = psz_text,
+        .u.question = {
+            .i_type = i_type,
+            .psz_cancel = psz_cancel,
+            .psz_action1 = psz_action1,
+            .psz_action2 = psz_action2,
+        }
+    };
+
+    int i_ret = dialog_display(p_provider, pp_id, &dialog);
+    free(psz_text);
+    return i_ret;
+}
+
+int
+vlc_dialog_wait_question_va(vlc_object_t *p_obj,
+                            vlc_dialog_question_type i_type,
+                            const char *psz_cancel, const char *psz_action1,
+                            const char *psz_action2, const char *psz_title,
+                            const char *psz_fmt, va_list ap)
+{
+    assert(p_obj != NULL && psz_fmt != NULL && psz_title != NULL
+        && psz_cancel != NULL);
+
+    vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
+    if (p_provider == NULL)
+        return VLC_EGENERIC;
+
+    vlc_dialog_id *p_id;
+    int i_ret = dialog_display_question_va(p_provider, &p_id, i_type,
+                                           psz_cancel, psz_action1,
+                                           psz_action2, psz_title, psz_fmt, ap);
+    if (i_ret < 0 || p_id == NULL)
+        return i_ret;
+
+    struct dialog_answer answer;
+    i_ret = dialog_wait(p_provider, p_id, VLC_DIALOG_QUESTION, &answer);
+    if (i_ret <= 0)
+        return i_ret;
 
-    vlc_object_t *provider = dialog_GetProvider (obj);
-    if (provider == NULL)
-        return 0;
+    if (answer.u.question.i_action != 1 && answer.u.question.i_action != 2)
+        return VLC_EGENERIC;
+
+    return answer.u.question.i_action;
+}
 
-    char *text;
+#undef vlc_dialog_wait_question
+int
+vlc_dialog_wait_question(vlc_object_t *p_obj,
+                         vlc_dialog_question_type i_type,
+                         const char *psz_cancel, const char *psz_action1,
+                         const char *psz_action2, const char *psz_title,
+                         const char *psz_fmt, ...)
+{
+    assert(psz_fmt != NULL);
     va_list ap;
-    int answer = 0;
+    va_start(ap, psz_fmt);
+    int i_ret = vlc_dialog_wait_question_va(p_obj, i_type, psz_cancel,
+                                            psz_action1, psz_action2, psz_title,
+                                            psz_fmt, ap);
+    va_end(ap);
+    return i_ret;
+}
 
-    va_start (ap, cancel);
-    if (vasprintf (&text, fmt, ap) != -1)
+static int
+display_progress_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
+                    bool b_indeterminate, float f_position,
+                    const char *psz_cancel, const char *psz_title,
+                    const char *psz_fmt, va_list ap)
+{
+    char *psz_text;
+    if (vasprintf(&psz_text, psz_fmt, ap) == -1)
+        return VLC_ENOMEM;
+
+    vlc_dialog dialog = {
+        .i_type = VLC_DIALOG_PROGRESS,
+        .psz_title = psz_title,
+        .psz_text = psz_text,
+        .u.progress = {
+            .b_indeterminate = b_indeterminate,
+            .f_position = f_position,
+            .psz_cancel = psz_cancel,
+        }
+    };
+
+    int i_ret = dialog_display(p_provider, pp_id, &dialog);
+    if (i_ret == VLC_SUCCESS && *pp_id != NULL)
     {
-        dialog_question_t dialog = { title, text, yes, no, cancel, 0, };
-        var_SetAddress (provider, "dialog-question", &dialog);
-        answer = dialog.answer;
-        free (text);
+        vlc_dialog_id *p_id = *pp_id;
+        vlc_mutex_lock(&p_provider->lock);
+        p_id->b_progress_indeterminate = b_indeterminate;
+        p_id->psz_progress_text = psz_text;
+        psz_text = NULL;
+        vlc_mutex_unlock(&p_provider->lock);
     }
-    va_end (ap);
-    vlc_object_release (provider);
-    return answer;
+    free(psz_text);
+    return i_ret;
 }
 
-#undef dialog_ProgressCreate
-/**
- * Creates a progress bar dialog.
- */
-dialog_progress_bar_t *
-dialog_ProgressCreate (vlc_object_t *obj, const char *title,
-                       const char *message, const char *cancel)
+vlc_dialog_id *
+vlc_dialog_display_progress_va(vlc_object_t *p_obj, bool b_indeterminate,
+                               float f_position, const char *psz_cancel,
+                               const char *psz_title, const char *psz_fmt,
+                               va_list ap)
 {
-    if (obj->i_flags & OBJECT_FLAGS_NOINTERACT)
-        return NULL;
+    assert(p_obj != NULL && psz_title != NULL && psz_fmt != NULL);
 
-    vlc_object_t *provider = dialog_GetProvider (obj);
-    if (provider == NULL)
+    vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
+    if (p_provider == NULL)
         return NULL;
+    vlc_dialog_id *p_id;
+    int i_ret = display_progress_va(p_provider, &p_id, b_indeterminate,
+                                    f_position, psz_cancel, psz_title, psz_fmt,
+                                    ap);
+    return i_ret == VLC_SUCCESS ? p_id : NULL;
+}
 
-    dialog_progress_bar_t *dialog = malloc (sizeof (*dialog));
-    if (dialog != NULL)
+#undef vlc_dialog_display_progress
+vlc_dialog_id *
+vlc_dialog_display_progress(vlc_object_t *p_obj, bool b_indeterminate,
+                            float f_position, const char *psz_cancel,
+                            const char *psz_title, const char *psz_fmt, ...)
+{
+    assert(psz_fmt != NULL);
+    va_list ap;
+    va_start(ap, psz_fmt);
+    vlc_dialog_id *p_id =
+        vlc_dialog_display_progress_va(p_obj, b_indeterminate, f_position,
+                                       psz_cancel, psz_title, psz_fmt, ap);
+    va_end(ap);
+    return p_id;
+}
+
+static int
+dialog_id_update_progress(vlc_dialog_id *p_id, float f_value, char *psz_text)
+{
+    assert(p_id != NULL);
+    vlc_dialog_provider *p_provider = p_id->p_provider;
+    assert(p_provider != NULL);
+
+    vlc_mutex_lock(&p_provider->lock);
+    if (p_provider->cbs.pf_update_progress == NULL)
     {
-        dialog->title = title;
-        dialog->message = message;
-        dialog->cancel = cancel;
-        var_SetAddress (provider, "dialog-progress-bar", dialog);
-#ifndef NDEBUG
-        dialog->title = dialog->message = dialog->cancel = NULL;
-#endif
-        assert (dialog->pf_update);
-        assert (dialog->pf_check);
-        assert (dialog->pf_destroy);
+        vlc_mutex_unlock(&p_provider->lock);
+        free(psz_text);
+        return VLC_EGENERIC;
+    }
+
+    if (p_id->b_progress_indeterminate)
+    {
+        vlc_mutex_unlock(&p_provider->lock);
+        free(psz_text);
+        return VLC_EGENERIC;
+    }
+    if (psz_text != NULL)
+    {
+        free(p_id->psz_progress_text);
+        p_id->psz_progress_text = psz_text;
     }
+    p_provider->cbs.pf_update_progress(p_id, f_value, p_id->psz_progress_text,
+                                       p_provider->p_cbs_data);
 
-    /* FIXME: This could conceivably crash if the dialog provider is destroyed
-     * before the dialog user. Holding the provider does not help, as it only
-     * protects object variable operations. For instance, it does not prevent
-     * unloading of the interface plugin. In the short term, the only solution
-     * is to not use progress dialog after deinitialization of the interfaces.
-     */
-    vlc_object_release (provider);
-    return dialog;
+    vlc_mutex_unlock(&p_provider->lock);
+    return VLC_SUCCESS;
 }
 
-void dialog_ProgressDestroy (dialog_progress_bar_t *dialog)
+int
+vlc_dialog_id_update_progress(vlc_dialog_id *p_id, float f_value)
 {
-    assert (dialog);
+    assert(p_id!= NULL);
 
-    dialog->pf_destroy (dialog->p_sys);
-    free (dialog);
+    return dialog_id_update_progress(p_id, f_value, NULL);
 }
 
-void dialog_ProgressSet (dialog_progress_bar_t *dialog, const char *text,
-                         float value)
+int
+vlc_dialog_id_update_progress_text_va(vlc_dialog_id *p_id, float f_value,
+                                      const char *psz_fmt, va_list ap)
 {
-    assert (dialog);
+    assert(p_id != NULL);
 
-    dialog->pf_update (dialog->p_sys, text, value);
+    char *psz_text;
+    if (vasprintf(&psz_text, psz_fmt, ap) == -1)
+        return VLC_ENOMEM;
+    return dialog_id_update_progress(p_id, f_value, psz_text);
 }
 
-bool dialog_ProgressCancelled (dialog_progress_bar_t *dialog)
+int
+vlc_dialog_id_update_progress_text(vlc_dialog_id *p_id, float f_value,
+                                   const char *psz_fmt, ...)
 {
-    assert (dialog);
+    assert(psz_fmt != NULL);
+    va_list ap;
+    va_start(ap, psz_fmt);
+    int i_ret = vlc_dialog_id_update_progress_text_va(p_id, f_value, psz_fmt, ap);
+    va_end(ap);
+    return i_ret;
+}
 
-    return dialog->pf_check (dialog->p_sys);
+void
+vlc_dialog_id_release(vlc_dialog_id *p_id)
+{
+    assert(p_id != NULL);
+    vlc_dialog_provider *p_provider = p_id->p_provider;
+    assert(p_provider != NULL);
+
+    vlc_mutex_lock(&p_provider->lock);
+    dialog_cancel_locked(p_provider, p_id);
+    dialog_remove_locked(p_provider, p_id, false);
+    vlc_mutex_unlock(&p_provider->lock);
 }
 
-#undef dialog_ExtensionUpdate
-int dialog_ExtensionUpdate (vlc_object_t *obj, extension_dialog_t *dialog)
+bool
+vlc_dialog_id_is_cancelled(vlc_dialog_id *p_id)
 {
-    assert (obj);
-    assert (dialog);
+    assert(p_id != NULL);
 
-    vlc_object_t *dp = dialog_GetProvider(obj);
-    if (!dp)
+    vlc_mutex_lock(&p_id->lock);
+    bool b_cancelled = p_id->b_cancelled;
+    vlc_mutex_unlock(&p_id->lock);
+    return b_cancelled;
+}
+
+void
+vlc_dialog_id_set_context(vlc_dialog_id *p_id, void *p_context)
+{
+    vlc_mutex_lock(&p_id->lock);
+    p_id->p_context = p_context;
+    vlc_mutex_unlock(&p_id->lock);
+}
+
+void *
+vlc_dialog_id_get_context(vlc_dialog_id *p_id)
+{
+    vlc_mutex_lock(&p_id->lock);
+    void *p_context = p_id->p_context;
+    vlc_mutex_unlock(&p_id->lock);
+    return p_context;
+}
+
+static int
+dialog_id_post(vlc_dialog_id *p_id, struct dialog_answer *p_answer)
+{
+    vlc_mutex_lock(&p_id->lock);
+    if (p_answer == NULL)
     {
-        msg_Warn (obj, "Dialog provider is not set, can't update dialog '%s'",
-                  dialog->psz_title);
-        return VLC_EGENERIC;
+        p_id->b_cancelled = true;
+    }
+    else
+    {
+        p_id->answer = *p_answer;
+        p_id->b_answered = true;
+    }
+    p_id->i_refcount--;
+    if (p_id->i_refcount > 0)
+    {
+        vlc_cond_signal(&p_id->wait);
+        vlc_mutex_unlock(&p_id->lock);
+    }
+    else
+    {
+        vlc_mutex_unlock(&p_id->lock);
+        dialog_id_release(p_id);
     }
+    return VLC_SUCCESS;
+}
 
-    // Signaling the dialog provider
-    int ret = var_SetAddress (dp, "dialog-extension", dialog);
+int
+vlc_dialog_id_post_login(vlc_dialog_id *p_id, const char *psz_username,
+                         const char *psz_password, bool b_store)
+{
+    assert(p_id != NULL && psz_username != NULL && psz_password != NULL);
+
+    struct dialog_answer answer = {
+        .i_type = VLC_DIALOG_LOGIN,
+        .u.login = {
+            .b_store = b_store,
+            .psz_username = strdup(psz_username),
+            .psz_password = strdup(psz_password),
+        },
+    };
+    if (answer.u.login.psz_username == NULL
+     || answer.u.login.psz_password == NULL)
+    {
+        free(answer.u.login.psz_username);
+        free(answer.u.login.psz_password);
+        dialog_id_post(p_id, NULL);
+        return VLC_ENOMEM;
+    }
 
-    vlc_object_release (dp);
-    return ret;
+    return dialog_id_post(p_id, &answer);
+}
+
+int
+vlc_dialog_id_post_action(vlc_dialog_id *p_id, int i_action)
+{
+    assert(p_id != NULL);
+
+    struct dialog_answer answer = {
+        .i_type = VLC_DIALOG_QUESTION,
+        .u.question = { .i_action = i_action },
+    };
+
+    return dialog_id_post(p_id, &answer);
+}
+
+int
+vlc_dialog_id_dismiss(vlc_dialog_id *p_id)
+{
+    return dialog_id_post(p_id, NULL);
 }
diff --git a/src/libvlc.c b/src/libvlc.c
index a7d9a69..964e586 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -61,6 +61,7 @@
 #include <vlc_interface.h>
 
 #include <vlc_charset.h>
+#include <vlc_dialog.h>
 #include <vlc_fs.h>
 #include <vlc_cpu.h>
 #include <vlc_url.h>
@@ -235,6 +236,14 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     }
 #endif
 
+    priv->p_dialog_provider = vlc_dialog_provider_new();
+    if( priv->p_dialog_provider == NULL )
+    {
+        vlc_LogDeinit (p_libvlc);
+        module_EndBank (true);
+        return VLC_ENOMEM;
+    }
+
 /* FIXME: could be replaced by using Unix sockets */
 #ifdef HAVE_DBUS
 
@@ -503,6 +512,8 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
     libvlc_Quit( p_libvlc );
     intf_DestroyAll( p_libvlc );
 
+    vlc_dialog_provider_release( priv->p_dialog_provider );
+
 #ifdef ENABLE_VLM
     /* Destroy VLM if created in libvlc_InternalInit */
     if( priv->p_vlm )
diff --git a/src/libvlc.h b/src/libvlc.h
index e18ee37..d198581 100644
--- a/src/libvlc.h
+++ b/src/libvlc.h
@@ -138,6 +138,8 @@ module_t *module_find_by_shortcut (const char *psz_shortcut);
 /**
  * Private LibVLC instance data.
  */
+typedef struct vlc_dialog_provider vlc_dialog_provider;
+
 typedef struct libvlc_priv_t
 {
     libvlc_int_t       public_data;
@@ -148,7 +150,7 @@ typedef struct libvlc_priv_t
     /* Singleton objects */
     vlc_logger_t      *logger;
     vlm_t             *p_vlm;  ///< the VLM singleton (or NULL)
-    vlc_object_t      *p_dialog_provider; ///< dialog provider
+    vlc_dialog_provider *p_dialog_provider; ///< dialog provider
     struct playlist_t *playlist; ///< Playlist for interfaces
     struct playlist_preparser_t *parser; ///< Input item meta data handler
     struct vlc_actions *actions; ///< Hotkeys handler
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 62ef785..d36d6ed 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -95,16 +95,6 @@ demux_New
 demux_vaControl
 demux_vaControlHelper
 dialog_ExtensionUpdate
-dialog_Login
-dialog_vaLogin
-dialog_ProgressCancelled
-dialog_ProgressCreate
-dialog_ProgressDestroy
-dialog_ProgressSet
-dialog_Question
-dialog_Register
-dialog_Unregister
-dialog_VFatal
 EndMD5
 es_format_Clean
 es_format_Copy
@@ -526,6 +516,27 @@ vlc_credential_init
 vlc_credential_clean
 vlc_credential_get
 vlc_credential_store
+vlc_dialog_display_error
+vlc_dialog_display_error_va
+vlc_dialog_display_progress
+vlc_dialog_display_progress_va
+vlc_dialog_id_dismiss
+vlc_dialog_id_get_context
+vlc_dialog_id_is_cancelled
+vlc_dialog_id_post_action
+vlc_dialog_id_post_login
+vlc_dialog_id_release
+vlc_dialog_id_set_context
+vlc_dialog_id_update_progress
+vlc_dialog_id_update_progress_text
+vlc_dialog_id_update_progress_text_va
+vlc_dialog_provider_new
+vlc_dialog_provider_release
+vlc_dialog_provider_set_callbacks
+vlc_dialog_wait_login
+vlc_dialog_wait_login_va
+vlc_dialog_wait_question
+vlc_dialog_wait_question_va
 vlc_sem_init
 vlc_sem_destroy
 vlc_sem_post
diff --git a/src/misc/keystore.c b/src/misc/keystore.c
index 62c7603..638fab5 100644
--- a/src/misc/keystore.c
+++ b/src/misc/keystore.c
@@ -395,37 +395,38 @@ vlc_credential_get(vlc_credential *p_credential, vlc_object_t *p_parent,
                 return false;
             char *psz_dialog_username = NULL;
             char *psz_dialog_password = NULL;
-
             va_list ap;
             va_start(ap, psz_dialog_fmt);
-            dialog_vaLogin(p_parent, p_credential->psz_username,
-                           &psz_dialog_username, &psz_dialog_password,
-                           p_credential->p_keystore ? &p_credential->b_store : NULL,
-                           psz_dialog_title, psz_dialog_fmt, ap);
+            bool *p_store = p_credential->p_keystore != NULL ?
+                            &p_credential->b_store : NULL;
+            int i_ret =
+                vlc_dialog_wait_login_va(p_parent,
+                                         &psz_dialog_username,
+                                         &psz_dialog_password, p_store,
+                                         p_credential->psz_username,
+                                         psz_dialog_title, psz_dialog_fmt, ap);
             va_end(ap);
 
-            /* Free previous dialog strings after dialog_vaLogin call since
-             * p_credential->psz_username (default username) can be a pointer
-             * to p_credential->psz_dialog_username */
+            /* Free previous dialog strings after vlc_dialog_wait_login_va call
+             * since p_credential->psz_username (default username) can be a
+             * pointer to p_credential->psz_dialog_username */
             free(p_credential->psz_dialog_username);
             free(p_credential->psz_dialog_password);
             p_credential->psz_dialog_username = psz_dialog_username;
             p_credential->psz_dialog_password = psz_dialog_password;
 
-            if (p_credential->psz_dialog_username
-             && p_credential->psz_dialog_password)
-            {
-                p_credential->psz_username = p_credential->psz_dialog_username;
-                p_credential->psz_password = p_credential->psz_dialog_password;
-
-                if (protocol_is_smb(p_url))
-                    smb_split_domain(p_credential);
-            }
-            else
+            if (i_ret != 1)
             {
                 p_credential->psz_username = p_credential->psz_password = NULL;
                 return false;
             }
+
+            p_credential->psz_username = p_credential->psz_dialog_username;
+            p_credential->psz_password = p_credential->psz_dialog_password;
+
+            if (protocol_is_smb(p_url))
+                smb_split_domain(p_credential);
+
             break;
         }
     }
diff --git a/src/misc/update.c b/src/misc/update.c
index 1d7f765..a5f14e1 100644
--- a/src/misc/update.c
+++ b/src/misc/update.c
@@ -88,6 +88,10 @@
 # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status" UPDATE_OS_SUFFIX
 #endif
 
+#define dialog_FatalWait( p_obj, psz_title, psz_fmt, ... ) \
+    vlc_dialog_wait_question( p_obj, VLC_DIALOG_QUESTION_CRITICAL, "OK", NULL, \
+                              NULL, psz_title, psz_fmt, ##__VA_ARGS__ );
+
 /*****************************************************************************
  * Update_t functions
  *****************************************************************************/
@@ -525,11 +529,11 @@ void update_Download( update_t *p_update, const char *psz_destdir )
 static void* update_DownloadReal( void *obj )
 {
     update_download_thread_t *p_udt = (update_download_thread_t *)obj;
-    dialog_progress_bar_t *p_progress = NULL;
+    int i_ret;
+    unsigned int i_dialog_id = 0;
     uint64_t l_size;
     uint64_t l_downloaded = 0;
     float f_progress;
-    char *psz_status;
     char *psz_downloaded = NULL;
     char *psz_size = NULL;
     char *psz_destfile = NULL;
@@ -589,20 +593,21 @@ static void* update_DownloadReal( void *obj )
     msg_Dbg( p_udt, "Downloading Stream '%s'", p_update->release.psz_url );
 
     psz_size = size_str( l_size );
-    if( asprintf( &psz_status, _("%s\nDownloading... %s/%s %.1f%% done"),
-        p_update->release.psz_url, "0.0", psz_size, 0.0 ) == -1 )
-        goto end;
 
-    p_progress = dialog_ProgressCreate( p_udt, _( "Downloading..."),
-                                        psz_status, _("Cancel") );
+    i_ret =
+        vlc_dialog_display_progress( p_udt, false, 0.0, _("Cancel"),
+                                     ( "Downloading..."),
+                                     _("%s\nDownloading... %s/%s %.1f%% done"),
+                                     p_update->release.psz_url, "0.0", psz_size,
+                                     0.0 );
 
-    free( psz_status );
-    if( p_progress == NULL )
+    if( i_ret <= 0 )
         goto end;
+    i_dialog_id = i_ret;
 
     while( !atomic_load( &p_udt->aborted ) &&
            ( i_read = stream_Read( p_stream, p_buffer, 1 << 10 ) ) &&
-           !dialog_ProgressCancelled( p_progress ) )
+           !vlc_dialog_cancelled( p_udt, i_dialog_id ) )
     {
         if( fwrite( p_buffer, i_read, 1, p_file ) < 1 )
         {
@@ -614,13 +619,11 @@ static void* update_DownloadReal( void *obj )
         psz_downloaded = size_str( l_downloaded );
         f_progress = (float)l_downloaded/(float)l_size;
 
-        if( asprintf( &psz_status, _( "%s\nDownloading... %s/%s - %.1f%% done" ),
-                      p_update->release.psz_url, psz_downloaded, psz_size,
-                      f_progress*100 ) != -1 )
-        {
-            dialog_ProgressSet( p_progress, psz_status, f_progress );
-            free( psz_status );
-        }
+        vlc_dialog_update_progress_text( p_udt, i_dialog_id, f_pos,
+                                         "%s\nDownloading... %s/%s - %.1f%% done",
+                                         p_update->release.psz_url,
+                                         psz_downloaded, psz_size,
+                                         f_progress*100 );
         free( psz_downloaded );
     }
 
@@ -629,10 +632,10 @@ static void* update_DownloadReal( void *obj )
     p_file = NULL;
 
     if( !atomic_load( &p_udt->aborted ) &&
-        !dialog_ProgressCancelled( p_progress ) )
+        !vlc_dialog_cancelled( p_udt, i_dialog_id ) )
     {
-        dialog_ProgressDestroy( p_progress );
-        p_progress = NULL;
+        vlc_dialog_cancel( p_udt, i_dialog_id );
+        i_dialog_id = 0;
     }
     else
     {
@@ -719,10 +722,13 @@ static void* update_DownloadReal( void *obj )
     free( p_hash );
 
 #ifdef _WIN32
-    int answer = dialog_Question( p_udt, _("Update VLC media player"),
-    _("The new version was successfully downloaded. Do you want to close VLC and install it now?"),
-    _("Install"), _("Cancel"), NULL);
-
+    static const char *psz_msg =
+        _("The new version was successfully downloaded."
+        "Do you want to close VLC and install it now?");
+    int answer = vlc_dialog_wait_question( p_udt, VLC_DIALOG_QUESTION_NORMAL,
+                                           _("Cancel"), _("Install"), NULL,
+                                           _("Update VLC media player"),
+                                           psz_msg );
     if(answer == 1)
     {
         wchar_t psz_wdestfile[MAX_PATH];
@@ -733,8 +739,8 @@ static void* update_DownloadReal( void *obj )
     }
 #endif
 end:
-    if( p_progress )
-        dialog_ProgressDestroy( p_progress );
+    if( i_dialog_id != 0 )
+        vlc_dialog_cancel( p_udt, i_dialog_id );
     if( p_stream )
         stream_Delete( p_stream );
     if( p_file )
diff --git a/test/modules/misc/tls.c b/test/modules/misc/tls.c
index d7f4a2c..6f12b56 100644
--- a/test/modules/misc/tls.c
+++ b/test/modules/misc/tls.c
@@ -47,18 +47,19 @@ static int tlspair(int fds[2])
     return vlc_socketpair(PF_LOCAL, SOCK_STREAM, 0, fds, true);
 }
 
-static int question_callback(vlc_object_t *obj, const char *varname,
-                             vlc_value_t old, vlc_value_t cur, void *data)
+static bool dialog_display_cb(vlc_dialog_id *id, vlc_dialog *dialog, void *data)
 {
-    dialog_question_t *q = cur.p_address;
+    if (dialog->i_type != VLC_DIALOG_QUESTION)
+        return false;
     int *value = data;
+    vlc_dialog_id_post_action(id, *value);
+    return true;
+}
 
-    q->answer = *value;
-
-    assert(obj == VLC_OBJECT(obj->p_libvlc));
-    assert(!strcmp(varname, "dialog-question"));
-    (void) old;
-    return VLC_SUCCESS;
+static void dialog_cancel_cb(vlc_dialog_id *id, void *data)
+{
+    (void)data;
+    vlc_dialog_id_dismiss(id);
 }
 
 static libvlc_instance_t *vlc;
@@ -172,9 +173,12 @@ int main(void)
     client_creds = vlc_tls_ClientCreate(obj);
     assert(client_creds != NULL);
 
-    var_Create(obj, "dialog-question", VLC_VAR_ADDRESS);
-    var_AddCallback(obj, "dialog-question", question_callback, &answer);
-    dialog_Register(obj);
+    vlc_dialog_cbs cbs = {
+        dialog_display_cb,
+        dialog_cancel_cb,
+        NULL,
+    };
+    vlc_dialog_provider_set_callbacks(obj, &cbs, &answer);
 
     vlc_thread_t th;
     vlc_tls_t *tls;
@@ -188,7 +192,7 @@ int main(void)
     assert(val == -1);
 
     /* Accept unknown certificate */
-    answer = 2;
+    answer = 1;
     val = securepair(&th, &tls, alpnv, &alp);
     assert(val == 0);
     assert(alp != NULL);
@@ -269,8 +273,7 @@ int main(void)
     vlc_tls_Close(tls);
     vlc_join(th, NULL);
 
-    dialog_Unregister(obj);
-    var_DelCallback(obj, "dialog-question", question_callback, &answer);
+    vlc_dialog_provider_set_callbacks(obj, NULL, NULL);
     vlc_tls_Delete(client_creds);
     vlc_tls_Delete(server_creds);
     libvlc_release(vlc);
-- 
2.7.0.rc3



More information about the vlc-devel mailing list