1 /*****************************************************************************
2 * dialog.c: User dialog functions
3 *****************************************************************************
4 * Copyright © 2009 Rémi Denis-Courmont
5 * Copyright © 2016 VLC authors and VideoLAN
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
21
22 /** @ingroup vlc_dialog */
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <stdarg.h>
28
29 #include <vlc_common.h>
30 #include <vlc_dialog.h>
31 #include <vlc_interrupt.h>
32 #include <vlc_extensions.h>
33 #include <assert.h>
34 #include "libvlc.h"
35
36 struct vlc_dialog_provider
37 {
38 vlc_mutex_t lock;
39 vlc_array_t dialog_array;
40 vlc_dialog_cbs cbs;
41 void * p_cbs_data;
42
43 vlc_dialog_ext_update_cb pf_ext_update;
44 void * p_ext_data;
45 };
46
47 enum dialog_type
48 {
49 VLC_DIALOG_ERROR,
50 VLC_DIALOG_LOGIN,
51 VLC_DIALOG_QUESTION,
52 VLC_DIALOG_PROGRESS,
53 };
54
55 struct dialog_answer
56 {
57 enum dialog_type i_type;
58 union
59 {
60 struct
61 {
62 char *psz_username;
63 char *psz_password;
64 bool b_store;
65 } login;
66 struct
67 {
68 int i_action;
69 } question;
70 } u;
71 };
72
73 struct dialog
74 {
75 enum dialog_type i_type;
76 const char *psz_title;
77 const char *psz_text;
78
79 union
80 {
81 struct
82 {
83 const char *psz_default_username;
84 bool b_ask_store;
85 } login;
86 struct
87 {
88 vlc_dialog_question_type i_type;
89 const char *psz_cancel;
90 const char *psz_action1;
91 const char *psz_action2;
92 } question;
93 struct
94 {
95 bool b_indeterminate;
96 float f_position;
97 const char *psz_cancel;
98 } progress;
99 } u;
100 };
101
102 struct vlc_dialog_id
103 {
104 vlc_mutex_t lock;
105 vlc_cond_t wait;
106 enum dialog_type i_type;
107 void * p_context;
108 int i_refcount;
109 bool b_cancelled;
110 bool b_answered;
111 bool b_progress_indeterminate;
112 char * psz_progress_text;
113 struct dialog_answer answer;
114 };
115
116 struct dialog_i11e_context
117 {
118 vlc_dialog_provider * p_provider;
119 vlc_dialog_id * p_id;
120 };
121
122 static inline vlc_dialog_provider *
get_dialog_provider(vlc_object_t * p_obj,bool b_check_interact)123 get_dialog_provider(vlc_object_t *p_obj, bool b_check_interact)
124 {
125 if (b_check_interact && p_obj->obj.flags & OBJECT_FLAGS_NOINTERACT)
126 return NULL;
127
128 vlc_dialog_provider *p_provider =
129 libvlc_priv(p_obj->obj.libvlc)->p_dialog_provider;
130 assert(p_provider != NULL);
131 return p_provider;
132 }
133
134 static void
dialog_id_release(vlc_dialog_id * p_id)135 dialog_id_release(vlc_dialog_id *p_id)
136 {
137 if (p_id->answer.i_type == VLC_DIALOG_LOGIN)
138 {
139 free(p_id->answer.u.login.psz_username);
140 free(p_id->answer.u.login.psz_password);
141 }
142 free(p_id->psz_progress_text);
143 vlc_mutex_destroy(&p_id->lock);
144 vlc_cond_destroy(&p_id->wait);
145 free(p_id);
146 }
147
148 int
libvlc_InternalDialogInit(libvlc_int_t * p_libvlc)149 libvlc_InternalDialogInit(libvlc_int_t *p_libvlc)
150 {
151 assert(p_libvlc != NULL);
152 vlc_dialog_provider *p_provider = malloc(sizeof(*p_provider));
153 if (p_provider == NULL)
154 return VLC_EGENERIC;
155
156 vlc_mutex_init(&p_provider->lock);
157 vlc_array_init(&p_provider->dialog_array);
158
159 memset(&p_provider->cbs, 0, sizeof(p_provider->cbs));
160 p_provider->p_cbs_data = NULL;
161
162 p_provider->pf_ext_update = NULL;
163 p_provider->p_ext_data = NULL;
164 libvlc_priv(p_libvlc)->p_dialog_provider = p_provider;
165
166 return VLC_SUCCESS;
167 }
168
169 static void
dialog_cancel_locked(vlc_dialog_provider * p_provider,vlc_dialog_id * p_id)170 dialog_cancel_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id)
171 {
172 vlc_mutex_lock(&p_id->lock);
173 if (p_id->b_cancelled || p_id->b_answered)
174 {
175 vlc_mutex_unlock(&p_id->lock);
176 return;
177 }
178 p_id->b_cancelled = true;
179 vlc_mutex_unlock(&p_id->lock);
180
181 p_provider->cbs.pf_cancel(p_provider->p_cbs_data, p_id);
182 }
183
184 static vlc_dialog_id *
dialog_add_locked(vlc_dialog_provider * p_provider,enum dialog_type i_type)185 dialog_add_locked(vlc_dialog_provider *p_provider, enum dialog_type i_type)
186 {
187 vlc_dialog_id *p_id = calloc(1, sizeof(*p_id));
188
189 if (p_id == NULL)
190 return NULL;
191
192 if(vlc_array_append(&p_provider->dialog_array, p_id))
193 {
194 free(p_id);
195 return NULL;
196 }
197
198 vlc_mutex_init(&p_id->lock);
199 vlc_cond_init(&p_id->wait);
200
201 p_id->i_type = i_type;
202 p_id->i_refcount = 2; /* provider and callbacks */
203
204 return p_id;
205 }
206
207 static void
dialog_remove_locked(vlc_dialog_provider * p_provider,vlc_dialog_id * p_id)208 dialog_remove_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id)
209 {
210 ssize_t i_idx = vlc_array_index_of_item(&p_provider->dialog_array, p_id);
211 assert(i_idx >= 0);
212 vlc_array_remove(&p_provider->dialog_array, i_idx);
213
214 vlc_mutex_lock(&p_id->lock);
215 p_id->i_refcount--;
216 if (p_id->i_refcount == 0)
217 {
218 vlc_mutex_unlock(&p_id->lock);
219 dialog_id_release(p_id);
220 }
221 else
222 vlc_mutex_unlock(&p_id->lock);
223 }
224
225 static void
dialog_clear_all_locked(vlc_dialog_provider * p_provider)226 dialog_clear_all_locked(vlc_dialog_provider *p_provider)
227 {
228 for (size_t i = 0; i < vlc_array_count(&p_provider->dialog_array); ++i)
229 {
230 vlc_dialog_id *p_id =
231 vlc_array_item_at_index(&p_provider->dialog_array, i);
232 dialog_cancel_locked(p_provider, p_id);
233 }
234 }
235
236 void
libvlc_InternalDialogClean(libvlc_int_t * p_libvlc)237 libvlc_InternalDialogClean(libvlc_int_t *p_libvlc)
238 {
239 assert(p_libvlc != NULL);
240 vlc_dialog_provider *p_provider = libvlc_priv(p_libvlc)->p_dialog_provider;
241
242 if (p_provider == NULL)
243 return;
244 vlc_mutex_lock(&p_provider->lock);
245 dialog_clear_all_locked(p_provider);
246 vlc_mutex_unlock(&p_provider->lock);
247
248 vlc_mutex_destroy(&p_provider->lock);
249 free(p_provider);
250 libvlc_priv(p_libvlc)->p_dialog_provider = NULL;
251 }
252
253 #undef vlc_dialog_provider_set_callbacks
254 void
vlc_dialog_provider_set_callbacks(vlc_object_t * p_obj,const vlc_dialog_cbs * p_cbs,void * p_data)255 vlc_dialog_provider_set_callbacks(vlc_object_t *p_obj,
256 const vlc_dialog_cbs *p_cbs, void *p_data)
257 {
258 assert(p_obj != NULL);
259 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
260
261 vlc_mutex_lock(&p_provider->lock);
262 dialog_clear_all_locked(p_provider);
263
264 if (p_cbs == NULL)
265 {
266 memset(&p_provider->cbs, 0, sizeof(p_provider->cbs));
267 p_provider->p_cbs_data = NULL;
268 }
269 else
270 {
271 p_provider->cbs = *p_cbs;
272 p_provider->p_cbs_data = p_data;
273 }
274 vlc_mutex_unlock(&p_provider->lock);
275 }
276
277 static void
dialog_wait_interrupted(void * p_data)278 dialog_wait_interrupted(void *p_data)
279 {
280 struct dialog_i11e_context *p_context = p_data;
281 vlc_dialog_provider *p_provider = p_context->p_provider;
282 vlc_dialog_id *p_id = p_context->p_id;
283
284 vlc_mutex_lock(&p_provider->lock);
285 dialog_cancel_locked(p_provider, p_id);
286 vlc_mutex_unlock(&p_provider->lock);
287
288 vlc_mutex_lock(&p_id->lock);
289 vlc_cond_signal(&p_id->wait);
290 vlc_mutex_unlock(&p_id->lock);
291 }
292
293 static int
dialog_wait(vlc_dialog_provider * p_provider,vlc_dialog_id * p_id,enum dialog_type i_type,struct dialog_answer * p_answer)294 dialog_wait(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id,
295 enum dialog_type i_type, struct dialog_answer *p_answer)
296 {
297 struct dialog_i11e_context context = {
298 .p_provider = p_provider,
299 .p_id = p_id,
300 };
301 vlc_interrupt_register(dialog_wait_interrupted, &context);
302
303 vlc_mutex_lock(&p_id->lock);
304 /* Wait for the dialog to be dismissed, interrupted or answered */
305 while (!p_id->b_cancelled && !p_id->b_answered)
306 vlc_cond_wait(&p_id->wait, &p_id->lock);
307
308 int i_ret;
309 if (p_id->b_cancelled)
310 i_ret = 0;
311 else if (p_id->answer.i_type != i_type)
312 i_ret = VLC_EGENERIC;
313 else
314 {
315 i_ret = 1;
316 memcpy(p_answer, &p_id->answer, sizeof(p_id->answer));
317 memset(&p_id->answer, 0, sizeof(p_id->answer));
318 }
319
320 vlc_mutex_unlock(&p_id->lock);
321 vlc_interrupt_unregister();
322
323 vlc_mutex_lock(&p_provider->lock);
324 dialog_remove_locked(p_provider, p_id);
325 vlc_mutex_unlock(&p_provider->lock);
326 return i_ret;
327 }
328
329 static int
dialog_display_error_va(vlc_dialog_provider * p_provider,const char * psz_title,const char * psz_fmt,va_list ap)330 dialog_display_error_va(vlc_dialog_provider *p_provider, const char *psz_title,
331 const char *psz_fmt, va_list ap)
332 {
333 vlc_mutex_lock(&p_provider->lock);
334 if (p_provider->cbs.pf_display_error == NULL)
335 {
336 vlc_mutex_unlock(&p_provider->lock);
337 return VLC_EGENERIC;
338 }
339
340 char *psz_text;
341 if (vasprintf(&psz_text, psz_fmt, ap) == -1)
342 {
343 vlc_mutex_unlock(&p_provider->lock);
344 return VLC_ENOMEM;
345 }
346
347 p_provider->cbs.pf_display_error(p_provider->p_cbs_data, psz_title, psz_text);
348 free(psz_text);
349 vlc_mutex_unlock(&p_provider->lock);
350
351 return VLC_SUCCESS;
352 }
353
354 int
vlc_dialog_display_error_va(vlc_object_t * p_obj,const char * psz_title,const char * psz_fmt,va_list ap)355 vlc_dialog_display_error_va(vlc_object_t *p_obj, const char *psz_title,
356 const char *psz_fmt, va_list ap)
357 {
358 assert(p_obj != NULL && psz_title != NULL && psz_fmt != NULL);
359 int i_ret;
360 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
361
362 if (p_provider != NULL)
363 i_ret = dialog_display_error_va(p_provider, psz_title, psz_fmt, ap);
364 else
365 i_ret = VLC_EGENERIC;
366
367 if (i_ret != VLC_SUCCESS)
368 {
369 msg_Err(p_obj, "%s", psz_title);
370 msg_GenericVa(p_obj, VLC_MSG_ERR, psz_fmt, ap);
371 }
372 return i_ret;
373 }
374
375
376 #undef vlc_dialog_display_error
377 int
vlc_dialog_display_error(vlc_object_t * p_obj,const char * psz_title,const char * psz_fmt,...)378 vlc_dialog_display_error(vlc_object_t *p_obj, const char *psz_title,
379 const char *psz_fmt, ...)
380 {
381 assert(psz_fmt != NULL);
382 va_list ap;
383 va_start(ap, psz_fmt);
384 int i_ret = vlc_dialog_display_error_va(p_obj, psz_title, psz_fmt, ap);
385 va_end(ap);
386 return i_ret;
387 }
388
389 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)390 dialog_display_login_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
391 const char *psz_default_username, bool b_ask_store,
392 const char *psz_title, const char *psz_fmt, va_list ap)
393 {
394 vlc_mutex_lock(&p_provider->lock);
395 if (p_provider->cbs.pf_display_login == NULL
396 || p_provider->cbs.pf_cancel == NULL)
397 {
398 vlc_mutex_unlock(&p_provider->lock);
399 return VLC_EGENERIC;
400 }
401
402 char *psz_text;
403 if (vasprintf(&psz_text, psz_fmt, ap) == -1)
404 {
405 vlc_mutex_unlock(&p_provider->lock);
406 return VLC_ENOMEM;
407 }
408
409 vlc_dialog_id *p_id = dialog_add_locked(p_provider, VLC_DIALOG_LOGIN);
410 if (p_id == NULL)
411 {
412 free(psz_text);
413 vlc_mutex_unlock(&p_provider->lock);
414 return VLC_ENOMEM;
415 }
416 p_provider->cbs.pf_display_login(p_provider->p_cbs_data, p_id, psz_title,
417 psz_text, psz_default_username, b_ask_store);
418 free(psz_text);
419 vlc_mutex_unlock(&p_provider->lock);
420 *pp_id = p_id;
421
422 return VLC_SUCCESS;
423 }
424
425 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)426 vlc_dialog_wait_login_va(vlc_object_t *p_obj, char **ppsz_username,
427 char **ppsz_password, bool *p_store,
428 const char *psz_default_username,
429 const char *psz_title, const char *psz_fmt, va_list ap)
430 {
431 assert(p_obj != NULL && ppsz_username != NULL && ppsz_password != NULL
432 && psz_fmt != NULL && psz_title != NULL);
433
434 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
435 if (p_provider == NULL)
436 return VLC_EGENERIC;
437
438 vlc_dialog_id *p_id;
439 int i_ret = dialog_display_login_va(p_provider, &p_id, psz_default_username,
440 p_store != NULL, psz_title, psz_fmt, ap);
441 if (i_ret < 0 || p_id == NULL)
442 return i_ret;
443
444 struct dialog_answer answer;
445 i_ret = dialog_wait(p_provider, p_id, VLC_DIALOG_LOGIN, &answer);
446 if (i_ret <= 0)
447 return i_ret;
448
449 *ppsz_username = answer.u.login.psz_username;
450 *ppsz_password = answer.u.login.psz_password;
451 if (p_store != NULL)
452 *p_store = answer.u.login.b_store;
453
454 return 1;
455 }
456
457 #undef vlc_dialog_wait_login
458 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,...)459 vlc_dialog_wait_login(vlc_object_t *p_obj, char **ppsz_username,
460 char **ppsz_password, bool *p_store,
461 const char *psz_default_username, const char *psz_title,
462 const char *psz_fmt, ...)
463 {
464 assert(psz_fmt != NULL);
465 va_list ap;
466 va_start(ap, psz_fmt);
467 int i_ret = vlc_dialog_wait_login_va(p_obj, ppsz_username, ppsz_password,
468 p_store,psz_default_username,
469 psz_title, psz_fmt, ap);
470 va_end(ap);
471 return i_ret;
472 }
473
474 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)475 dialog_display_question_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
476 vlc_dialog_question_type i_type,
477 const char *psz_cancel, const char *psz_action1,
478 const char *psz_action2, const char *psz_title,
479 const char *psz_fmt, va_list ap)
480 {
481 vlc_mutex_lock(&p_provider->lock);
482 if (p_provider->cbs.pf_display_question == NULL
483 || p_provider->cbs.pf_cancel == NULL)
484 {
485 vlc_mutex_unlock(&p_provider->lock);
486 return VLC_EGENERIC;
487 }
488
489 char *psz_text;
490 if (vasprintf(&psz_text, psz_fmt, ap) == -1)
491 {
492 vlc_mutex_unlock(&p_provider->lock);
493 return VLC_ENOMEM;
494 }
495
496 vlc_dialog_id *p_id = dialog_add_locked(p_provider, VLC_DIALOG_QUESTION);
497 if (p_id == NULL)
498 {
499 free(psz_text);
500 vlc_mutex_unlock(&p_provider->lock);
501 return VLC_ENOMEM;
502 }
503 p_provider->cbs.pf_display_question(p_provider->p_cbs_data, p_id, psz_title,
504 psz_text, i_type, psz_cancel, psz_action1,
505 psz_action2);
506 free(psz_text);
507 vlc_mutex_unlock(&p_provider->lock);
508 *pp_id = p_id;
509
510 return VLC_SUCCESS;
511 }
512
513 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)514 vlc_dialog_wait_question_va(vlc_object_t *p_obj,
515 vlc_dialog_question_type i_type,
516 const char *psz_cancel, const char *psz_action1,
517 const char *psz_action2, const char *psz_title,
518 const char *psz_fmt, va_list ap)
519 {
520 assert(p_obj != NULL && psz_fmt != NULL && psz_title != NULL
521 && psz_cancel != NULL);
522
523 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
524 if (p_provider == NULL)
525 return VLC_EGENERIC;
526
527 vlc_dialog_id *p_id;
528 int i_ret = dialog_display_question_va(p_provider, &p_id, i_type,
529 psz_cancel, psz_action1,
530 psz_action2, psz_title, psz_fmt, ap);
531 if (i_ret < 0 || p_id == NULL)
532 return i_ret;
533
534 struct dialog_answer answer;
535 i_ret = dialog_wait(p_provider, p_id, VLC_DIALOG_QUESTION, &answer);
536 if (i_ret <= 0)
537 return i_ret;
538
539 if (answer.u.question.i_action != 1 && answer.u.question.i_action != 2)
540 return VLC_EGENERIC;
541
542 return answer.u.question.i_action;
543 }
544
545 #undef vlc_dialog_wait_question
546 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,...)547 vlc_dialog_wait_question(vlc_object_t *p_obj,
548 vlc_dialog_question_type i_type,
549 const char *psz_cancel, const char *psz_action1,
550 const char *psz_action2, const char *psz_title,
551 const char *psz_fmt, ...)
552 {
553 assert(psz_fmt != NULL);
554 va_list ap;
555 va_start(ap, psz_fmt);
556 int i_ret = vlc_dialog_wait_question_va(p_obj, i_type, psz_cancel,
557 psz_action1, psz_action2, psz_title,
558 psz_fmt, ap);
559 va_end(ap);
560 return i_ret;
561 }
562
563 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)564 display_progress_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
565 bool b_indeterminate, float f_position,
566 const char *psz_cancel, const char *psz_title,
567 const char *psz_fmt, va_list ap)
568 {
569 vlc_mutex_lock(&p_provider->lock);
570 if (p_provider->cbs.pf_display_progress == NULL
571 || p_provider->cbs.pf_update_progress == NULL
572 || p_provider->cbs.pf_cancel == NULL)
573 {
574 vlc_mutex_unlock(&p_provider->lock);
575 return VLC_EGENERIC;
576 }
577
578 char *psz_text;
579 if (vasprintf(&psz_text, psz_fmt, ap) == -1)
580 {
581 vlc_mutex_unlock(&p_provider->lock);
582 return VLC_ENOMEM;
583 }
584
585 vlc_dialog_id *p_id = dialog_add_locked(p_provider, VLC_DIALOG_PROGRESS);
586 if (p_id == NULL)
587 {
588 free(psz_text);
589 vlc_mutex_unlock(&p_provider->lock);
590 return VLC_ENOMEM;
591 }
592 p_id->b_progress_indeterminate = b_indeterminate;
593 p_id->psz_progress_text = psz_text;
594 p_provider->cbs.pf_display_progress(p_provider->p_cbs_data, p_id, psz_title,
595 psz_text, b_indeterminate, f_position,
596 psz_cancel);
597 vlc_mutex_unlock(&p_provider->lock);
598 *pp_id = p_id;
599
600 return VLC_SUCCESS;
601 }
602
603 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)604 vlc_dialog_display_progress_va(vlc_object_t *p_obj, bool b_indeterminate,
605 float f_position, const char *psz_cancel,
606 const char *psz_title, const char *psz_fmt,
607 va_list ap)
608 {
609 assert(p_obj != NULL && psz_title != NULL && psz_fmt != NULL);
610
611 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
612 if (p_provider == NULL)
613 return NULL;
614 vlc_dialog_id *p_id;
615 int i_ret = display_progress_va(p_provider, &p_id, b_indeterminate,
616 f_position, psz_cancel, psz_title, psz_fmt,
617 ap);
618 return i_ret == VLC_SUCCESS ? p_id : NULL;
619 }
620
621 #undef vlc_dialog_display_progress
622 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,...)623 vlc_dialog_display_progress(vlc_object_t *p_obj, bool b_indeterminate,
624 float f_position, const char *psz_cancel,
625 const char *psz_title, const char *psz_fmt, ...)
626 {
627 assert(psz_fmt != NULL);
628 va_list ap;
629 va_start(ap, psz_fmt);
630 vlc_dialog_id *p_id =
631 vlc_dialog_display_progress_va(p_obj, b_indeterminate, f_position,
632 psz_cancel, psz_title, psz_fmt, ap);
633 va_end(ap);
634 return p_id;
635 }
636
637 static int
dialog_update_progress(vlc_object_t * p_obj,vlc_dialog_id * p_id,float f_value,char * psz_text)638 dialog_update_progress(vlc_object_t *p_obj, vlc_dialog_id *p_id, float f_value,
639 char *psz_text)
640 {
641 assert(p_obj != NULL && p_id != NULL);
642 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
643
644 vlc_mutex_lock(&p_provider->lock);
645 if (p_provider->cbs.pf_update_progress == NULL ||
646 vlc_dialog_is_cancelled(p_obj, p_id))
647 {
648 vlc_mutex_unlock(&p_provider->lock);
649 free(psz_text);
650 return VLC_EGENERIC;
651 }
652
653 if (p_id->b_progress_indeterminate)
654 f_value = 0.0f;
655
656 if (psz_text != NULL)
657 {
658 free(p_id->psz_progress_text);
659 p_id->psz_progress_text = psz_text;
660 }
661 p_provider->cbs.pf_update_progress(p_provider->p_cbs_data, p_id, f_value,
662 p_id->psz_progress_text);
663
664 vlc_mutex_unlock(&p_provider->lock);
665 return VLC_SUCCESS;
666 }
667
668 #undef vlc_dialog_update_progress
669 int
vlc_dialog_update_progress(vlc_object_t * p_obj,vlc_dialog_id * p_id,float f_value)670 vlc_dialog_update_progress(vlc_object_t *p_obj, vlc_dialog_id *p_id,
671 float f_value)
672 {
673 return dialog_update_progress(p_obj, p_id, f_value, NULL);
674 }
675
676 int
vlc_dialog_update_progress_text_va(vlc_object_t * p_obj,vlc_dialog_id * p_id,float f_value,const char * psz_fmt,va_list ap)677 vlc_dialog_update_progress_text_va(vlc_object_t *p_obj, vlc_dialog_id *p_id,
678 float f_value, const char *psz_fmt,
679 va_list ap)
680 {
681 assert(psz_fmt != NULL);
682
683 char *psz_text;
684 if (vasprintf(&psz_text, psz_fmt, ap) == -1)
685 return VLC_ENOMEM;
686 return dialog_update_progress(p_obj, p_id, f_value, psz_text);
687 }
688
689 #undef vlc_dialog_update_progress_text
690 int
vlc_dialog_update_progress_text(vlc_object_t * p_obj,vlc_dialog_id * p_id,float f_value,const char * psz_fmt,...)691 vlc_dialog_update_progress_text(vlc_object_t *p_obj, vlc_dialog_id *p_id,
692 float f_value, const char *psz_fmt, ...)
693 {
694 assert(psz_fmt != NULL);
695 va_list ap;
696 va_start(ap, psz_fmt);
697 int i_ret = vlc_dialog_update_progress_text_va(p_obj, p_id, f_value,
698 psz_fmt, ap);
699 va_end(ap);
700 return i_ret;
701 }
702
703 #undef vlc_dialog_release
704 void
vlc_dialog_release(vlc_object_t * p_obj,vlc_dialog_id * p_id)705 vlc_dialog_release(vlc_object_t *p_obj, vlc_dialog_id *p_id)
706 {
707 assert(p_obj != NULL && p_id != NULL);
708 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
709
710 vlc_mutex_lock(&p_provider->lock);
711 dialog_cancel_locked(p_provider, p_id);
712 dialog_remove_locked(p_provider, p_id);
713 vlc_mutex_unlock(&p_provider->lock);
714 }
715
716 #undef vlc_dialog_is_cancelled
717 bool
vlc_dialog_is_cancelled(vlc_object_t * p_obj,vlc_dialog_id * p_id)718 vlc_dialog_is_cancelled(vlc_object_t *p_obj, vlc_dialog_id *p_id)
719 {
720 (void) p_obj;
721 assert(p_id != NULL);
722
723 vlc_mutex_lock(&p_id->lock);
724 bool b_cancelled = p_id->b_cancelled;
725 vlc_mutex_unlock(&p_id->lock);
726 return b_cancelled;
727 }
728
729 void
vlc_dialog_id_set_context(vlc_dialog_id * p_id,void * p_context)730 vlc_dialog_id_set_context(vlc_dialog_id *p_id, void *p_context)
731 {
732 vlc_mutex_lock(&p_id->lock);
733 p_id->p_context = p_context;
734 vlc_mutex_unlock(&p_id->lock);
735 }
736
737 void *
vlc_dialog_id_get_context(vlc_dialog_id * p_id)738 vlc_dialog_id_get_context(vlc_dialog_id *p_id)
739 {
740 assert(p_id != NULL);
741 vlc_mutex_lock(&p_id->lock);
742 void *p_context = p_id->p_context;
743 vlc_mutex_unlock(&p_id->lock);
744 return p_context;
745 }
746
747 static int
dialog_id_post(vlc_dialog_id * p_id,struct dialog_answer * p_answer)748 dialog_id_post(vlc_dialog_id *p_id, struct dialog_answer *p_answer)
749 {
750 vlc_mutex_lock(&p_id->lock);
751 if (p_answer == NULL)
752 {
753 p_id->b_cancelled = true;
754 }
755 else
756 {
757 p_id->answer = *p_answer;
758 p_id->b_answered = true;
759 }
760 p_id->i_refcount--;
761 if (p_id->i_refcount > 0)
762 {
763 vlc_cond_signal(&p_id->wait);
764 vlc_mutex_unlock(&p_id->lock);
765 }
766 else
767 {
768 vlc_mutex_unlock(&p_id->lock);
769 dialog_id_release(p_id);
770 }
771 return VLC_SUCCESS;
772 }
773
774 int
vlc_dialog_id_post_login(vlc_dialog_id * p_id,const char * psz_username,const char * psz_password,bool b_store)775 vlc_dialog_id_post_login(vlc_dialog_id *p_id, const char *psz_username,
776 const char *psz_password, bool b_store)
777 {
778 assert(p_id != NULL && psz_username != NULL && psz_password != NULL);
779
780 struct dialog_answer answer = {
781 .i_type = VLC_DIALOG_LOGIN,
782 .u.login = {
783 .b_store = b_store,
784 .psz_username = strdup(psz_username),
785 .psz_password = strdup(psz_password),
786 },
787 };
788 if (answer.u.login.psz_username == NULL
789 || answer.u.login.psz_password == NULL)
790 {
791 free(answer.u.login.psz_username);
792 free(answer.u.login.psz_password);
793 dialog_id_post(p_id, NULL);
794 return VLC_ENOMEM;
795 }
796
797 return dialog_id_post(p_id, &answer);
798 }
799
800 int
vlc_dialog_id_post_action(vlc_dialog_id * p_id,int i_action)801 vlc_dialog_id_post_action(vlc_dialog_id *p_id, int i_action)
802 {
803 assert(p_id != NULL);
804
805 struct dialog_answer answer = {
806 .i_type = VLC_DIALOG_QUESTION,
807 .u.question = { .i_action = i_action },
808 };
809
810 return dialog_id_post(p_id, &answer);
811 }
812
813 int
vlc_dialog_id_dismiss(vlc_dialog_id * p_id)814 vlc_dialog_id_dismiss(vlc_dialog_id *p_id)
815 {
816 return dialog_id_post(p_id, NULL);
817 }
818
819 #undef vlc_dialog_provider_set_ext_callback
820 void
vlc_dialog_provider_set_ext_callback(vlc_object_t * p_obj,vlc_dialog_ext_update_cb pf_update,void * p_data)821 vlc_dialog_provider_set_ext_callback(vlc_object_t *p_obj,
822 vlc_dialog_ext_update_cb pf_update,
823 void *p_data)
824 {
825 assert(p_obj != NULL);
826 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
827
828 vlc_mutex_lock(&p_provider->lock);
829
830 p_provider->pf_ext_update = pf_update;
831 p_provider->p_ext_data = p_data;
832
833 vlc_mutex_unlock(&p_provider->lock);
834 }
835
836 #undef vlc_ext_dialog_update
837 int
vlc_ext_dialog_update(vlc_object_t * p_obj,extension_dialog_t * p_ext_dialog)838 vlc_ext_dialog_update(vlc_object_t *p_obj, extension_dialog_t *p_ext_dialog)
839 {
840 assert(p_obj != NULL);
841 vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
842
843 vlc_mutex_lock(&p_provider->lock);
844 if (p_provider->pf_ext_update == NULL)
845 {
846 vlc_mutex_unlock(&p_provider->lock);
847 return VLC_EGENERIC;
848 }
849 p_provider->pf_ext_update(p_ext_dialog, p_provider->p_ext_data);
850 vlc_mutex_unlock(&p_provider->lock);
851 return VLC_SUCCESS;
852 }
853