qt: playlist: use item title if available
[vlc.git] / src / interface / dialog.c
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 *
123 get_dialog_provider(vlc_object_t *p_obj, bool b_check_interact)
124 {
125     if ((b_check_interact && p_obj->no_interact) || vlc_killed())
126         return NULL;
127
128     vlc_dialog_provider *p_provider =
129         libvlc_priv(vlc_object_instance(p_obj))->p_dialog_provider;
130     assert(p_provider != NULL);
131     return p_provider;
132 }
133
134 static void
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     free(p_id);
144 }
145
146 int
147 libvlc_InternalDialogInit(libvlc_int_t *p_libvlc)
148 {
149     assert(p_libvlc != NULL);
150     vlc_dialog_provider *p_provider = malloc(sizeof(*p_provider));
151     if (p_provider == NULL)
152         return VLC_EGENERIC;
153
154     vlc_mutex_init(&p_provider->lock);
155     vlc_array_init(&p_provider->dialog_array);
156
157     memset(&p_provider->cbs, 0, sizeof(p_provider->cbs));
158     p_provider->p_cbs_data = NULL;
159
160     p_provider->pf_ext_update = NULL;
161     p_provider->p_ext_data = NULL;
162     libvlc_priv(p_libvlc)->p_dialog_provider = p_provider;
163
164     return VLC_SUCCESS;
165 }
166
167 static void
168 dialog_cancel_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id)
169 {
170     vlc_mutex_lock(&p_id->lock);
171     if (p_id->b_cancelled || p_id->b_answered)
172     {
173         vlc_mutex_unlock(&p_id->lock);
174         return;
175     }
176     p_id->b_cancelled = true;
177     vlc_mutex_unlock(&p_id->lock);
178
179     p_provider->cbs.pf_cancel(p_provider->p_cbs_data, p_id);
180 }
181
182 static vlc_dialog_id *
183 dialog_add_locked(vlc_dialog_provider *p_provider, enum dialog_type i_type)
184 {
185     vlc_dialog_id *p_id = calloc(1, sizeof(*p_id));
186
187     if (p_id == NULL)
188         return NULL;
189
190     if(vlc_array_append(&p_provider->dialog_array, p_id))
191     {
192         free(p_id);
193         return NULL;
194     }
195
196     vlc_mutex_init(&p_id->lock);
197     vlc_cond_init(&p_id->wait);
198
199     p_id->i_type = i_type;
200     p_id->i_refcount = 2; /* provider and callbacks */
201
202     return p_id;
203 }
204
205 static void
206 dialog_remove_locked(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id)
207 {
208     ssize_t i_idx = vlc_array_index_of_item(&p_provider->dialog_array, p_id);
209     assert(i_idx >= 0);
210     vlc_array_remove(&p_provider->dialog_array, i_idx);
211
212     vlc_mutex_lock(&p_id->lock);
213     p_id->i_refcount--;
214     if (p_id->i_refcount == 0)
215     {
216         vlc_mutex_unlock(&p_id->lock);
217         dialog_id_release(p_id);
218     }
219     else
220         vlc_mutex_unlock(&p_id->lock);
221 }
222
223 static void
224 dialog_clear_all_locked(vlc_dialog_provider *p_provider)
225 {
226     for (size_t i = 0; i < vlc_array_count(&p_provider->dialog_array); ++i)
227     {
228         vlc_dialog_id *p_id =
229             vlc_array_item_at_index(&p_provider->dialog_array, i);
230         dialog_cancel_locked(p_provider, p_id);
231     }
232 }
233
234 void
235 libvlc_InternalDialogClean(libvlc_int_t *p_libvlc)
236 {
237     assert(p_libvlc != NULL);
238     vlc_dialog_provider *p_provider = libvlc_priv(p_libvlc)->p_dialog_provider;
239
240     if (p_provider == NULL)
241         return;
242     vlc_mutex_lock(&p_provider->lock);
243     dialog_clear_all_locked(p_provider);
244     vlc_mutex_unlock(&p_provider->lock);
245
246     free(p_provider);
247     libvlc_priv(p_libvlc)->p_dialog_provider = NULL;
248 }
249
250 #undef vlc_dialog_provider_set_callbacks
251 void
252 vlc_dialog_provider_set_callbacks(vlc_object_t *p_obj,
253                                   const vlc_dialog_cbs *p_cbs, void *p_data)
254 {
255     assert(p_obj != NULL);
256     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
257
258     vlc_mutex_lock(&p_provider->lock);
259     dialog_clear_all_locked(p_provider);
260
261     if (p_cbs == NULL)
262     {
263         memset(&p_provider->cbs, 0, sizeof(p_provider->cbs));
264         p_provider->p_cbs_data = NULL;
265     }
266     else
267     {
268         p_provider->cbs = *p_cbs;
269         p_provider->p_cbs_data = p_data;
270     }
271     vlc_mutex_unlock(&p_provider->lock);
272 }
273
274 static void
275 dialog_wait_interrupted(void *p_data)
276 {
277     struct dialog_i11e_context *p_context = p_data;
278     vlc_dialog_provider *p_provider = p_context->p_provider;
279     vlc_dialog_id *p_id = p_context->p_id;
280
281     vlc_mutex_lock(&p_provider->lock);
282     dialog_cancel_locked(p_provider, p_id);
283     vlc_mutex_unlock(&p_provider->lock);
284
285     vlc_mutex_lock(&p_id->lock);
286     vlc_cond_signal(&p_id->wait);
287     vlc_mutex_unlock(&p_id->lock);
288 }
289
290 static int
291 dialog_wait(vlc_dialog_provider *p_provider, vlc_dialog_id *p_id,
292             enum dialog_type i_type, struct dialog_answer *p_answer)
293 {
294     struct dialog_i11e_context context = {
295         .p_provider = p_provider,
296         .p_id = p_id,
297     };
298     vlc_interrupt_register(dialog_wait_interrupted, &context);
299
300     vlc_mutex_lock(&p_id->lock);
301     /* Wait for the dialog to be dismissed, interrupted or answered */
302     while (!p_id->b_cancelled && !p_id->b_answered)
303         vlc_cond_wait(&p_id->wait, &p_id->lock);
304
305     int i_ret;
306     if (p_id->b_cancelled)
307         i_ret = 0;
308     else if (p_id->answer.i_type != i_type)
309         i_ret = VLC_EGENERIC;
310     else
311     {
312         i_ret = 1;
313         memcpy(p_answer, &p_id->answer, sizeof(p_id->answer));
314         memset(&p_id->answer, 0, sizeof(p_id->answer));
315     }
316
317     vlc_mutex_unlock(&p_id->lock);
318     vlc_interrupt_unregister();
319
320     vlc_mutex_lock(&p_provider->lock);
321     dialog_remove_locked(p_provider, p_id);
322     vlc_mutex_unlock(&p_provider->lock);
323     return i_ret;
324 }
325
326 static int
327 dialog_display_error_va(vlc_dialog_provider *p_provider, const char *psz_title,
328                         const char *psz_fmt, va_list ap)
329 {
330     vlc_mutex_lock(&p_provider->lock);
331     if (p_provider->cbs.pf_display_error == NULL)
332     {
333         vlc_mutex_unlock(&p_provider->lock);
334         return VLC_EGENERIC;
335     }
336
337     char *psz_text;
338     if (vasprintf(&psz_text, psz_fmt, ap) == -1)
339     {
340         vlc_mutex_unlock(&p_provider->lock);
341         return VLC_ENOMEM;
342     }
343
344     p_provider->cbs.pf_display_error(p_provider->p_cbs_data, psz_title, psz_text);
345     free(psz_text);
346     vlc_mutex_unlock(&p_provider->lock);
347
348     return VLC_SUCCESS;
349 }
350
351 int
352 vlc_dialog_display_error_va(vlc_object_t *p_obj, const char *psz_title,
353                             const char *psz_fmt, va_list ap)
354 {
355     assert(p_obj != NULL && psz_title != NULL && psz_fmt != NULL);
356     int i_ret;
357     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
358
359     if (p_provider != NULL)
360         i_ret = dialog_display_error_va(p_provider, psz_title, psz_fmt, ap);
361     else
362         i_ret = VLC_EGENERIC;
363
364     if (i_ret != VLC_SUCCESS)
365     {
366         msg_Err(p_obj, "%s", psz_title);
367         msg_GenericVa(p_obj, VLC_MSG_ERR, psz_fmt, ap);
368     }
369     return i_ret;
370 }
371
372
373 #undef vlc_dialog_display_error
374 int
375 vlc_dialog_display_error(vlc_object_t *p_obj, const char *psz_title,
376                          const char *psz_fmt, ...)
377 {
378     assert(psz_fmt != NULL);
379     va_list ap;
380     va_start(ap, psz_fmt);
381     int i_ret = vlc_dialog_display_error_va(p_obj, psz_title, psz_fmt, ap);
382     va_end(ap);
383     return i_ret;
384 }
385
386 static int
387 dialog_display_login_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
388                         const char *psz_default_username, bool b_ask_store,
389                         const char *psz_title, const char *psz_fmt, va_list ap)
390 {
391     vlc_mutex_lock(&p_provider->lock);
392     if (p_provider->cbs.pf_display_login == NULL
393      || p_provider->cbs.pf_cancel == NULL)
394     {
395         vlc_mutex_unlock(&p_provider->lock);
396         return VLC_EGENERIC;
397     }
398
399     char *psz_text;
400     if (vasprintf(&psz_text, psz_fmt, ap) == -1)
401     {
402         vlc_mutex_unlock(&p_provider->lock);
403         return VLC_ENOMEM;
404     }
405
406     vlc_dialog_id *p_id = dialog_add_locked(p_provider, VLC_DIALOG_LOGIN);
407     if (p_id == NULL)
408     {
409         free(psz_text);
410         vlc_mutex_unlock(&p_provider->lock);
411         return VLC_ENOMEM;
412     }
413     p_provider->cbs.pf_display_login(p_provider->p_cbs_data, p_id, psz_title,
414                                      psz_text, psz_default_username, b_ask_store);
415     free(psz_text);
416     vlc_mutex_unlock(&p_provider->lock);
417     *pp_id = p_id;
418
419     return VLC_SUCCESS;
420 }
421
422 int
423 vlc_dialog_wait_login_va(vlc_object_t *p_obj,  char **ppsz_username,
424                          char **ppsz_password, bool *p_store,
425                          const char *psz_default_username,
426                          const char *psz_title, const char *psz_fmt, va_list ap)
427 {
428     assert(p_obj != NULL && ppsz_username != NULL && ppsz_password != NULL
429         && psz_fmt != NULL && psz_title != NULL);
430
431     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
432     if (p_provider == NULL)
433         return VLC_EGENERIC;
434
435     vlc_dialog_id *p_id;
436     int i_ret = dialog_display_login_va(p_provider, &p_id, psz_default_username,
437                                         p_store != NULL, psz_title, psz_fmt, ap);
438     if (i_ret < 0 || p_id == NULL)
439         return i_ret;
440
441     struct dialog_answer answer;
442     i_ret = dialog_wait(p_provider, p_id, VLC_DIALOG_LOGIN, &answer);
443     if (i_ret <= 0)
444         return i_ret;
445
446     *ppsz_username = answer.u.login.psz_username;
447     *ppsz_password = answer.u.login.psz_password;
448     if (p_store != NULL)
449         *p_store = answer.u.login.b_store;
450
451     return 1;
452 }
453
454 #undef vlc_dialog_wait_login
455 int
456 vlc_dialog_wait_login(vlc_object_t *p_obj,  char **ppsz_username,
457                       char **ppsz_password, bool *p_store,
458                       const char *psz_default_username, const char *psz_title,
459                       const char *psz_fmt, ...)
460 {
461     assert(psz_fmt != NULL);
462     va_list ap;
463     va_start(ap, psz_fmt);
464     int i_ret = vlc_dialog_wait_login_va(p_obj, ppsz_username, ppsz_password,
465                                          p_store,psz_default_username,
466                                          psz_title, psz_fmt, ap);
467     va_end(ap);
468     return i_ret;
469 }
470
471 static int
472 dialog_display_question_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
473                            vlc_dialog_question_type i_type,
474                            const char *psz_cancel, const char *psz_action1,
475                            const char *psz_action2, const char *psz_title,
476                            const char *psz_fmt, va_list ap)
477 {
478     vlc_mutex_lock(&p_provider->lock);
479     if (p_provider->cbs.pf_display_question == NULL
480      || p_provider->cbs.pf_cancel == NULL)
481     {
482         vlc_mutex_unlock(&p_provider->lock);
483         return VLC_EGENERIC;
484     }
485
486     char *psz_text;
487     if (vasprintf(&psz_text, psz_fmt, ap) == -1)
488     {
489         vlc_mutex_unlock(&p_provider->lock);
490         return VLC_ENOMEM;
491     }
492
493     vlc_dialog_id *p_id = dialog_add_locked(p_provider, VLC_DIALOG_QUESTION);
494     if (p_id == NULL)
495     {
496         free(psz_text);
497         vlc_mutex_unlock(&p_provider->lock);
498         return VLC_ENOMEM;
499     }
500     p_provider->cbs.pf_display_question(p_provider->p_cbs_data, p_id, psz_title,
501                                         psz_text, i_type, psz_cancel, psz_action1,
502                                         psz_action2);
503     free(psz_text);
504     vlc_mutex_unlock(&p_provider->lock);
505     *pp_id = p_id;
506
507     return VLC_SUCCESS;
508 }
509
510 int
511 vlc_dialog_wait_question_va(vlc_object_t *p_obj,
512                             vlc_dialog_question_type i_type,
513                             const char *psz_cancel, const char *psz_action1,
514                             const char *psz_action2, const char *psz_title,
515                             const char *psz_fmt, va_list ap)
516 {
517     assert(p_obj != NULL && psz_fmt != NULL && psz_title != NULL
518         && psz_cancel != NULL);
519
520     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
521     if (p_provider == NULL)
522         return VLC_EGENERIC;
523
524     vlc_dialog_id *p_id;
525     int i_ret = dialog_display_question_va(p_provider, &p_id, i_type,
526                                            psz_cancel, psz_action1,
527                                            psz_action2, psz_title, psz_fmt, ap);
528     if (i_ret < 0 || p_id == NULL)
529         return i_ret;
530
531     struct dialog_answer answer;
532     i_ret = dialog_wait(p_provider, p_id, VLC_DIALOG_QUESTION, &answer);
533     if (i_ret <= 0)
534         return i_ret;
535
536     if (answer.u.question.i_action != 1 && answer.u.question.i_action != 2)
537         return VLC_EGENERIC;
538
539     return answer.u.question.i_action;
540 }
541
542 #undef vlc_dialog_wait_question
543 int
544 vlc_dialog_wait_question(vlc_object_t *p_obj,
545                          vlc_dialog_question_type i_type,
546                          const char *psz_cancel, const char *psz_action1,
547                          const char *psz_action2, const char *psz_title,
548                          const char *psz_fmt, ...)
549 {
550     assert(psz_fmt != NULL);
551     va_list ap;
552     va_start(ap, psz_fmt);
553     int i_ret = vlc_dialog_wait_question_va(p_obj, i_type, psz_cancel,
554                                             psz_action1, psz_action2, psz_title,
555                                             psz_fmt, ap);
556     va_end(ap);
557     return i_ret;
558 }
559
560 static int
561 display_progress_va(vlc_dialog_provider *p_provider, vlc_dialog_id **pp_id,
562                     bool b_indeterminate, float f_position,
563                     const char *psz_cancel, const char *psz_title,
564                     const char *psz_fmt, va_list ap)
565 {
566     vlc_mutex_lock(&p_provider->lock);
567     if (p_provider->cbs.pf_display_progress == NULL
568      || p_provider->cbs.pf_update_progress == NULL
569      || p_provider->cbs.pf_cancel == NULL)
570     {
571         vlc_mutex_unlock(&p_provider->lock);
572         return VLC_EGENERIC;
573     }
574
575     char *psz_text;
576     if (vasprintf(&psz_text, psz_fmt, ap) == -1)
577     {
578         vlc_mutex_unlock(&p_provider->lock);
579         return VLC_ENOMEM;
580     }
581
582     vlc_dialog_id *p_id = dialog_add_locked(p_provider, VLC_DIALOG_PROGRESS);
583     if (p_id == NULL)
584     {
585         free(psz_text);
586         vlc_mutex_unlock(&p_provider->lock);
587         return VLC_ENOMEM;
588     }
589     p_id->b_progress_indeterminate = b_indeterminate;
590     p_id->psz_progress_text = psz_text;
591     p_provider->cbs.pf_display_progress(p_provider->p_cbs_data, p_id, psz_title,
592                                         psz_text, b_indeterminate, f_position,
593                                         psz_cancel);
594     vlc_mutex_unlock(&p_provider->lock);
595     *pp_id = p_id;
596
597     return VLC_SUCCESS;
598 }
599
600 vlc_dialog_id *
601 vlc_dialog_display_progress_va(vlc_object_t *p_obj, bool b_indeterminate,
602                                float f_position, const char *psz_cancel,
603                                const char *psz_title, const char *psz_fmt,
604                                va_list ap)
605 {
606     assert(p_obj != NULL && psz_title != NULL && psz_fmt != NULL);
607
608     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, true);
609     if (p_provider == NULL)
610         return NULL;
611     vlc_dialog_id *p_id;
612     int i_ret = display_progress_va(p_provider, &p_id, b_indeterminate,
613                                     f_position, psz_cancel, psz_title, psz_fmt,
614                                     ap);
615     return i_ret == VLC_SUCCESS ? p_id : NULL;
616 }
617
618 #undef vlc_dialog_display_progress
619 vlc_dialog_id *
620 vlc_dialog_display_progress(vlc_object_t *p_obj, bool b_indeterminate,
621                             float f_position, const char *psz_cancel,
622                             const char *psz_title, const char *psz_fmt, ...)
623 {
624     assert(psz_fmt != NULL);
625     va_list ap;
626     va_start(ap, psz_fmt);
627     vlc_dialog_id *p_id =
628         vlc_dialog_display_progress_va(p_obj, b_indeterminate, f_position,
629                                        psz_cancel, psz_title, psz_fmt, ap);
630     va_end(ap);
631     return p_id;
632 }
633
634 static int
635 dialog_update_progress(vlc_object_t *p_obj, vlc_dialog_id *p_id, float f_value,
636                        char *psz_text)
637 {
638     assert(p_obj != NULL && p_id != NULL);
639     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
640
641     vlc_mutex_lock(&p_provider->lock);
642     if (p_provider->cbs.pf_update_progress == NULL ||
643         vlc_dialog_is_cancelled(p_obj, p_id))
644     {
645         vlc_mutex_unlock(&p_provider->lock);
646         free(psz_text);
647         return VLC_EGENERIC;
648     }
649
650     if (p_id->b_progress_indeterminate)
651         f_value = 0.0f;
652
653     if (psz_text != NULL)
654     {
655         free(p_id->psz_progress_text);
656         p_id->psz_progress_text = psz_text;
657     }
658     p_provider->cbs.pf_update_progress(p_provider->p_cbs_data, p_id, f_value,
659                                        p_id->psz_progress_text);
660
661     vlc_mutex_unlock(&p_provider->lock);
662     return VLC_SUCCESS;
663 }
664
665 #undef vlc_dialog_update_progress
666 int
667 vlc_dialog_update_progress(vlc_object_t *p_obj, vlc_dialog_id *p_id,
668                            float f_value)
669 {
670     return dialog_update_progress(p_obj, p_id, f_value, NULL);
671 }
672
673 int
674 vlc_dialog_update_progress_text_va(vlc_object_t *p_obj, vlc_dialog_id *p_id,
675                                    float f_value, const char *psz_fmt,
676                                    va_list ap)
677 {
678     assert(psz_fmt != NULL);
679
680     char *psz_text;
681     if (vasprintf(&psz_text, psz_fmt, ap) == -1)
682         return VLC_ENOMEM;
683     return dialog_update_progress(p_obj, p_id, f_value, psz_text);
684 }
685
686 #undef vlc_dialog_update_progress_text
687 int
688 vlc_dialog_update_progress_text(vlc_object_t *p_obj, vlc_dialog_id *p_id,
689                                 float f_value, const char *psz_fmt, ...)
690 {
691     assert(psz_fmt != NULL);
692     va_list ap;
693     va_start(ap, psz_fmt);
694     int i_ret = vlc_dialog_update_progress_text_va(p_obj, p_id, f_value,
695                                                    psz_fmt, ap);
696     va_end(ap);
697     return i_ret;
698 }
699
700 #undef vlc_dialog_release
701 void
702 vlc_dialog_release(vlc_object_t *p_obj, vlc_dialog_id *p_id)
703 {
704     assert(p_obj != NULL && p_id != NULL);
705     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
706
707     vlc_mutex_lock(&p_provider->lock);
708     dialog_cancel_locked(p_provider, p_id);
709     dialog_remove_locked(p_provider, p_id);
710     vlc_mutex_unlock(&p_provider->lock);
711 }
712
713 #undef vlc_dialog_is_cancelled
714 bool
715 vlc_dialog_is_cancelled(vlc_object_t *p_obj, vlc_dialog_id *p_id)
716 {
717     (void) p_obj;
718     assert(p_id != NULL);
719
720     vlc_mutex_lock(&p_id->lock);
721     bool b_cancelled = p_id->b_cancelled;
722     vlc_mutex_unlock(&p_id->lock);
723     return b_cancelled;
724 }
725
726 void
727 vlc_dialog_id_set_context(vlc_dialog_id *p_id, void *p_context)
728 {
729     vlc_mutex_lock(&p_id->lock);
730     p_id->p_context = p_context;
731     vlc_mutex_unlock(&p_id->lock);
732 }
733
734 void *
735 vlc_dialog_id_get_context(vlc_dialog_id *p_id)
736 {
737     assert(p_id != NULL);
738     vlc_mutex_lock(&p_id->lock);
739     void *p_context = p_id->p_context;
740     vlc_mutex_unlock(&p_id->lock);
741     return p_context;
742 }
743
744 static int
745 dialog_id_post(vlc_dialog_id *p_id, struct dialog_answer *p_answer)
746 {
747     vlc_mutex_lock(&p_id->lock);
748     if (p_answer == NULL)
749     {
750         p_id->b_cancelled = true;
751     }
752     else
753     {
754         p_id->answer = *p_answer;
755         p_id->b_answered = true;
756     }
757     p_id->i_refcount--;
758     if (p_id->i_refcount > 0)
759     {
760         vlc_cond_signal(&p_id->wait);
761         vlc_mutex_unlock(&p_id->lock);
762     }
763     else
764     {
765         vlc_mutex_unlock(&p_id->lock);
766         dialog_id_release(p_id);
767     }
768     return VLC_SUCCESS;
769 }
770
771 int
772 vlc_dialog_id_post_login(vlc_dialog_id *p_id, const char *psz_username,
773                          const char *psz_password, bool b_store)
774 {
775     assert(p_id != NULL && psz_username != NULL && psz_password != NULL);
776
777     struct dialog_answer answer = {
778         .i_type = VLC_DIALOG_LOGIN,
779         .u.login = {
780             .b_store = b_store,
781             .psz_username = strdup(psz_username),
782             .psz_password = strdup(psz_password),
783         },
784     };
785     if (answer.u.login.psz_username == NULL
786      || answer.u.login.psz_password == NULL)
787     {
788         free(answer.u.login.psz_username);
789         free(answer.u.login.psz_password);
790         dialog_id_post(p_id, NULL);
791         return VLC_ENOMEM;
792     }
793
794     return dialog_id_post(p_id, &answer);
795 }
796
797 int
798 vlc_dialog_id_post_action(vlc_dialog_id *p_id, int i_action)
799 {
800     assert(p_id != NULL);
801
802     struct dialog_answer answer = {
803         .i_type = VLC_DIALOG_QUESTION,
804         .u.question = { .i_action = i_action },
805     };
806
807     return dialog_id_post(p_id, &answer);
808 }
809
810 int
811 vlc_dialog_id_dismiss(vlc_dialog_id *p_id)
812 {
813     return dialog_id_post(p_id, NULL);
814 }
815
816 #undef vlc_dialog_provider_set_ext_callback
817 void
818 vlc_dialog_provider_set_ext_callback(vlc_object_t *p_obj,
819                                      vlc_dialog_ext_update_cb pf_update,
820                                      void *p_data)
821 {
822     assert(p_obj != NULL);
823     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
824
825     vlc_mutex_lock(&p_provider->lock);
826
827     p_provider->pf_ext_update = pf_update;
828     p_provider->p_ext_data = p_data;
829
830     vlc_mutex_unlock(&p_provider->lock);
831 }
832
833 #undef vlc_ext_dialog_update
834 int
835 vlc_ext_dialog_update(vlc_object_t *p_obj, extension_dialog_t *p_ext_dialog)
836 {
837     assert(p_obj != NULL);
838     vlc_dialog_provider *p_provider = get_dialog_provider(p_obj, false);
839
840     vlc_mutex_lock(&p_provider->lock);
841     if (p_provider->pf_ext_update == NULL)
842     {
843         vlc_mutex_unlock(&p_provider->lock);
844         return VLC_EGENERIC;
845     }
846     p_provider->pf_ext_update(p_ext_dialog, p_provider->p_ext_data);
847     vlc_mutex_unlock(&p_provider->lock);
848     return VLC_SUCCESS;
849 }