1 /*****************************************************************************
2 * dialog.c: User dialog functions
3 *****************************************************************************
4 * Copyright © 2009 Rémi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_dialog.h>
34 #include <vlc_extensions.h>
38 static vlc_mutex_t provider_lock
= VLC_STATIC_MUTEX
;
40 #undef dialog_Register
42 * Registers an object as the dialog provider.
43 * It is assumed that the appropriate variable callbacks are already
46 int dialog_Register (vlc_object_t
*obj
)
48 libvlc_priv_t
*priv
= libvlc_priv (obj
->p_libvlc
);
49 int ret
= VLC_EGENERIC
;
51 vlc_mutex_lock (&provider_lock
);
52 if (priv
->p_dialog_provider
== NULL
)
53 { /* Since the object is responsible for unregistering itself before
54 * it terminates, at reference is not needed. */
55 priv
->p_dialog_provider
= obj
;
58 vlc_mutex_unlock (&provider_lock
);
62 #undef dialog_Unregister
64 * Unregisters the dialog provider.
65 * Note that unless you have unregistered the callbacks already, the provider
66 * might still be in use by other threads. Also, you need to cancel all
67 * pending dialogs yourself.
69 int dialog_Unregister (vlc_object_t
*obj
)
71 libvlc_priv_t
*priv
= libvlc_priv (obj
->p_libvlc
);
72 int ret
= VLC_EGENERIC
;
74 vlc_mutex_lock (&provider_lock
);
75 if (priv
->p_dialog_provider
== obj
)
77 priv
->p_dialog_provider
= NULL
;
80 vlc_mutex_unlock (&provider_lock
);
84 static vlc_object_t
*dialog_GetProvider (vlc_object_t
*obj
)
86 libvlc_priv_t
*priv
= libvlc_priv (obj
->p_libvlc
);
87 vlc_object_t
*provider
;
89 vlc_mutex_lock (&provider_lock
);
90 if ((provider
= priv
->p_dialog_provider
) != NULL
)
91 vlc_object_hold (provider
);
92 vlc_mutex_unlock (&provider_lock
);
97 * Sends an error message through the user interface (if any).
98 * @param obj the VLC object emitting the error
99 * @param modal whether to wait for user to acknowledge the error
100 * before returning control to the caller
101 * @param title title of the error dialog
102 * @param fmt format string for the error message
103 * @param ap parameters list for the formatted error message
105 void dialog_VFatal (vlc_object_t
*obj
, bool modal
, const char *title
,
106 const char *fmt
, va_list ap
)
110 if (obj
->i_flags
& OBJECT_FLAGS_NOINTERACT
)
113 vlc_object_t
*provider
= dialog_GetProvider (obj
);
114 if (provider
== NULL
)
116 msg_Err (obj
, "%s", title
);
117 msg_GenericVa (obj
, VLC_MSG_ERR
, MODULE_STRING
, fmt
, ap
);
121 if (vasprintf (&text
, fmt
, ap
) != -1)
123 dialog_fatal_t dialog
= { title
, text
, };
124 var_SetAddress (provider
,
125 modal
? "dialog-critical" : "dialog-error", &dialog
);
128 vlc_object_release (provider
);
133 * Requests a username and password through the user interface.
134 * @param obj the VLC object requesting credential information
135 * @param username a pointer to the specified username [OUT]
136 * @param password a pointer to the specified password [OUT]
137 * @param title title for the dialog
138 * @param text format string for the message in the dialog
139 * @return Nothing. If a user name resp. a password was specified,
140 * it will be returned as a heap-allocated character array
141 * into the username resp password pointer. Those must be freed with free().
142 * Otherwise *username resp *password will be NULL.
144 void dialog_Login (vlc_object_t
*obj
, char **username
, char **password
,
145 const char *title
, const char *fmt
, ...)
147 assert ((username
!= NULL
) && (password
!= NULL
));
149 *username
= *password
= NULL
;
150 if (obj
->i_flags
& OBJECT_FLAGS_NOINTERACT
)
153 vlc_object_t
*provider
= dialog_GetProvider (obj
);
154 if (provider
== NULL
)
161 if (vasprintf (&text
, fmt
, ap
) != -1)
163 dialog_login_t dialog
= { title
, text
, username
, password
, };
164 var_SetAddress (provider
, "dialog-login", &dialog
);
168 vlc_object_release (provider
);
172 #undef dialog_Question
174 * Asks a total (Yes/No/Cancel) question through the user interface.
175 * @param obj VLC object emitting the question
176 * @param title dialog box title
177 * @param text dialog box text
178 * @param yes first choice/button text
179 * @param no second choice/button text
180 * @param cancel third answer/button text, or NULL if no third option
181 * @return 0 if the user could not answer the question (e.g. there is no UI),
182 * 1, 2 resp. 3 if the user pressed the first, second resp. third button.
184 int dialog_Question (vlc_object_t
*obj
, const char *title
, const char *text
,
185 const char *yes
, const char *no
, const char *cancel
)
187 if (obj
->i_flags
& OBJECT_FLAGS_NOINTERACT
)
190 vlc_object_t
*provider
= dialog_GetProvider (obj
);
191 if (provider
== NULL
)
194 dialog_question_t dialog
= { title
, text
, yes
, no
, cancel
, 0, };
195 var_SetAddress (provider
, "dialog-question", &dialog
);
196 vlc_object_release (provider
);
197 return dialog
.answer
;
200 #undef dialog_ProgressCreate
202 * Creates a progress bar dialog.
204 dialog_progress_bar_t
*
205 dialog_ProgressCreate (vlc_object_t
*obj
, const char *title
,
206 const char *message
, const char *cancel
)
208 if (obj
->i_flags
& OBJECT_FLAGS_NOINTERACT
)
211 vlc_object_t
*provider
= dialog_GetProvider (obj
);
212 if (provider
== NULL
)
215 dialog_progress_bar_t
*dialog
= malloc (sizeof (*dialog
));
218 dialog
->title
= title
;
219 dialog
->message
= message
;
220 dialog
->cancel
= cancel
;
221 var_SetAddress (provider
, "dialog-progress-bar", dialog
);
223 dialog
->title
= dialog
->message
= dialog
->cancel
= NULL
;
225 assert (dialog
->pf_update
);
226 assert (dialog
->pf_check
);
227 assert (dialog
->pf_destroy
);
230 /* FIXME: This could conceivably crash if the dialog provider is destroyed
231 * before the dialog user. Holding the provider does not help, as it only
232 * protects object variable operations. For instance, it does not prevent
233 * unloading of the interface plugin. In the short term, the only solution
234 * is to not use progress dialog after deinitialization of the interfaces.
236 vlc_object_release (provider
);
240 void dialog_ProgressDestroy (dialog_progress_bar_t
*dialog
)
244 dialog
->pf_destroy (dialog
->p_sys
);
248 void dialog_ProgressSet (dialog_progress_bar_t
*dialog
, const char *text
,
253 dialog
->pf_update (dialog
->p_sys
, text
, value
);
256 bool dialog_ProgressCancelled (dialog_progress_bar_t
*dialog
)
260 return dialog
->pf_check (dialog
->p_sys
);
263 #undef dialog_ExtensionUpdate
264 int dialog_ExtensionUpdate (vlc_object_t
*obj
, extension_dialog_t
*dialog
)
269 vlc_object_t
*dp
= dialog_GetProvider(obj
);
272 msg_Warn (obj
, "Dialog provider is not set, can't update dialog '%s'",
277 // Signaling the dialog provider
278 int ret
= var_SetAddress (dp
, "dialog-extension", dialog
);
280 vlc_object_release (dp
);