1 /*****************************************************************************
2 * dialog.c: User dialog functions
3 *****************************************************************************
4 * Copyright © 2009 Rémi Denis-Courmont
5 * Copyright © 2016 VLC authors and VideoLAN
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.
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.
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 *****************************************************************************/
22 /** @ingroup vlc_dialog */
29 #include <vlc_common.h>
30 #include <vlc_dialog.h>
31 #include <vlc_interrupt.h>
32 #include <vlc_extensions.h>
36 struct vlc_dialog_provider
39 vlc_array_t dialog_array
;
43 vlc_dialog_ext_update_cb pf_ext_update
;
57 enum dialog_type i_type
;
75 enum dialog_type i_type
;
76 const char *psz_title
;
83 const char *psz_default_username
;
88 vlc_dialog_question_type i_type
;
89 const char *psz_cancel
;
90 const char *psz_action1
;
91 const char *psz_action2
;
97 const char *psz_cancel
;
106 enum dialog_type i_type
;
111 bool b_progress_indeterminate
;
112 char * psz_progress_text
;
113 struct dialog_answer answer
;
116 struct dialog_i11e_context
118 vlc_dialog_provider
* p_provider
;
119 vlc_dialog_id
* p_id
;
122 static inline vlc_dialog_provider
*
123 get_dialog_provider(vlc_object_t
*p_obj
, bool b_check_interact
)
125 if ((b_check_interact
&& p_obj
->no_interact
) || vlc_killed())
128 vlc_dialog_provider
*p_provider
=
129 libvlc_priv(vlc_object_instance(p_obj
))->p_dialog_provider
;
130 assert(p_provider
!= NULL
);
135 dialog_id_release(vlc_dialog_id
*p_id
)
137 if (p_id
->answer
.i_type
== VLC_DIALOG_LOGIN
)
139 free(p_id
->answer
.u
.login
.psz_username
);
140 free(p_id
->answer
.u
.login
.psz_password
);
142 free(p_id
->psz_progress_text
);
147 libvlc_InternalDialogInit(libvlc_int_t
*p_libvlc
)
149 assert(p_libvlc
!= NULL
);
150 vlc_dialog_provider
*p_provider
= malloc(sizeof(*p_provider
));
151 if (p_provider
== NULL
)
154 vlc_mutex_init(&p_provider
->lock
);
155 vlc_array_init(&p_provider
->dialog_array
);
157 memset(&p_provider
->cbs
, 0, sizeof(p_provider
->cbs
));
158 p_provider
->p_cbs_data
= NULL
;
160 p_provider
->pf_ext_update
= NULL
;
161 p_provider
->p_ext_data
= NULL
;
162 libvlc_priv(p_libvlc
)->p_dialog_provider
= p_provider
;
168 dialog_cancel_locked(vlc_dialog_provider
*p_provider
, vlc_dialog_id
*p_id
)
170 vlc_mutex_lock(&p_id
->lock
);
171 if (p_id
->b_cancelled
|| p_id
->b_answered
)
173 vlc_mutex_unlock(&p_id
->lock
);
176 p_id
->b_cancelled
= true;
177 vlc_mutex_unlock(&p_id
->lock
);
179 p_provider
->cbs
.pf_cancel(p_provider
->p_cbs_data
, p_id
);
182 static vlc_dialog_id
*
183 dialog_add_locked(vlc_dialog_provider
*p_provider
, enum dialog_type i_type
)
185 vlc_dialog_id
*p_id
= calloc(1, sizeof(*p_id
));
190 if(vlc_array_append(&p_provider
->dialog_array
, p_id
))
196 vlc_mutex_init(&p_id
->lock
);
197 vlc_cond_init(&p_id
->wait
);
199 p_id
->i_type
= i_type
;
200 p_id
->i_refcount
= 2; /* provider and callbacks */
206 dialog_remove_locked(vlc_dialog_provider
*p_provider
, vlc_dialog_id
*p_id
)
208 ssize_t i_idx
= vlc_array_index_of_item(&p_provider
->dialog_array
, p_id
);
210 vlc_array_remove(&p_provider
->dialog_array
, i_idx
);
212 vlc_mutex_lock(&p_id
->lock
);
214 if (p_id
->i_refcount
== 0)
216 vlc_mutex_unlock(&p_id
->lock
);
217 dialog_id_release(p_id
);
220 vlc_mutex_unlock(&p_id
->lock
);
224 dialog_clear_all_locked(vlc_dialog_provider
*p_provider
)
226 for (size_t i
= 0; i
< vlc_array_count(&p_provider
->dialog_array
); ++i
)
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
);
235 libvlc_InternalDialogClean(libvlc_int_t
*p_libvlc
)
237 assert(p_libvlc
!= NULL
);
238 vlc_dialog_provider
*p_provider
= libvlc_priv(p_libvlc
)->p_dialog_provider
;
240 if (p_provider
== NULL
)
242 vlc_mutex_lock(&p_provider
->lock
);
243 dialog_clear_all_locked(p_provider
);
244 vlc_mutex_unlock(&p_provider
->lock
);
247 libvlc_priv(p_libvlc
)->p_dialog_provider
= NULL
;
250 #undef vlc_dialog_provider_set_callbacks
252 vlc_dialog_provider_set_callbacks(vlc_object_t
*p_obj
,
253 const vlc_dialog_cbs
*p_cbs
, void *p_data
)
255 assert(p_obj
!= NULL
);
256 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, false);
258 vlc_mutex_lock(&p_provider
->lock
);
259 dialog_clear_all_locked(p_provider
);
263 memset(&p_provider
->cbs
, 0, sizeof(p_provider
->cbs
));
264 p_provider
->p_cbs_data
= NULL
;
268 p_provider
->cbs
= *p_cbs
;
269 p_provider
->p_cbs_data
= p_data
;
271 vlc_mutex_unlock(&p_provider
->lock
);
275 dialog_wait_interrupted(void *p_data
)
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
;
281 vlc_mutex_lock(&p_provider
->lock
);
282 dialog_cancel_locked(p_provider
, p_id
);
283 vlc_mutex_unlock(&p_provider
->lock
);
285 vlc_mutex_lock(&p_id
->lock
);
286 vlc_cond_signal(&p_id
->wait
);
287 vlc_mutex_unlock(&p_id
->lock
);
291 dialog_wait(vlc_dialog_provider
*p_provider
, vlc_dialog_id
*p_id
,
292 enum dialog_type i_type
, struct dialog_answer
*p_answer
)
294 struct dialog_i11e_context context
= {
295 .p_provider
= p_provider
,
298 vlc_interrupt_register(dialog_wait_interrupted
, &context
);
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
);
306 if (p_id
->b_cancelled
)
308 else if (p_id
->answer
.i_type
!= i_type
)
309 i_ret
= VLC_EGENERIC
;
313 memcpy(p_answer
, &p_id
->answer
, sizeof(p_id
->answer
));
314 memset(&p_id
->answer
, 0, sizeof(p_id
->answer
));
317 vlc_mutex_unlock(&p_id
->lock
);
318 vlc_interrupt_unregister();
320 vlc_mutex_lock(&p_provider
->lock
);
321 dialog_remove_locked(p_provider
, p_id
);
322 vlc_mutex_unlock(&p_provider
->lock
);
327 dialog_display_error_va(vlc_dialog_provider
*p_provider
, const char *psz_title
,
328 const char *psz_fmt
, va_list ap
)
330 vlc_mutex_lock(&p_provider
->lock
);
331 if (p_provider
->cbs
.pf_display_error
== NULL
)
333 vlc_mutex_unlock(&p_provider
->lock
);
338 if (vasprintf(&psz_text
, psz_fmt
, ap
) == -1)
340 vlc_mutex_unlock(&p_provider
->lock
);
344 p_provider
->cbs
.pf_display_error(p_provider
->p_cbs_data
, psz_title
, psz_text
);
346 vlc_mutex_unlock(&p_provider
->lock
);
352 vlc_dialog_display_error_va(vlc_object_t
*p_obj
, const char *psz_title
,
353 const char *psz_fmt
, va_list ap
)
355 assert(p_obj
!= NULL
&& psz_title
!= NULL
&& psz_fmt
!= NULL
);
357 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, true);
359 if (p_provider
!= NULL
)
360 i_ret
= dialog_display_error_va(p_provider
, psz_title
, psz_fmt
, ap
);
362 i_ret
= VLC_EGENERIC
;
364 if (i_ret
!= VLC_SUCCESS
)
366 msg_Err(p_obj
, "%s", psz_title
);
367 msg_GenericVa(p_obj
, VLC_MSG_ERR
, psz_fmt
, ap
);
373 #undef vlc_dialog_display_error
375 vlc_dialog_display_error(vlc_object_t
*p_obj
, const char *psz_title
,
376 const char *psz_fmt
, ...)
378 assert(psz_fmt
!= NULL
);
380 va_start(ap
, psz_fmt
);
381 int i_ret
= vlc_dialog_display_error_va(p_obj
, psz_title
, psz_fmt
, ap
);
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
)
391 vlc_mutex_lock(&p_provider
->lock
);
392 if (p_provider
->cbs
.pf_display_login
== NULL
393 || p_provider
->cbs
.pf_cancel
== NULL
)
395 vlc_mutex_unlock(&p_provider
->lock
);
400 if (vasprintf(&psz_text
, psz_fmt
, ap
) == -1)
402 vlc_mutex_unlock(&p_provider
->lock
);
406 vlc_dialog_id
*p_id
= dialog_add_locked(p_provider
, VLC_DIALOG_LOGIN
);
410 vlc_mutex_unlock(&p_provider
->lock
);
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
);
416 vlc_mutex_unlock(&p_provider
->lock
);
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
)
428 assert(p_obj
!= NULL
&& ppsz_username
!= NULL
&& ppsz_password
!= NULL
429 && psz_fmt
!= NULL
&& psz_title
!= NULL
);
431 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, true);
432 if (p_provider
== NULL
)
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
)
441 struct dialog_answer answer
;
442 i_ret
= dialog_wait(p_provider
, p_id
, VLC_DIALOG_LOGIN
, &answer
);
446 *ppsz_username
= answer
.u
.login
.psz_username
;
447 *ppsz_password
= answer
.u
.login
.psz_password
;
449 *p_store
= answer
.u
.login
.b_store
;
454 #undef vlc_dialog_wait_login
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
, ...)
461 assert(psz_fmt
!= NULL
);
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
);
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
)
478 vlc_mutex_lock(&p_provider
->lock
);
479 if (p_provider
->cbs
.pf_display_question
== NULL
480 || p_provider
->cbs
.pf_cancel
== NULL
)
482 vlc_mutex_unlock(&p_provider
->lock
);
487 if (vasprintf(&psz_text
, psz_fmt
, ap
) == -1)
489 vlc_mutex_unlock(&p_provider
->lock
);
493 vlc_dialog_id
*p_id
= dialog_add_locked(p_provider
, VLC_DIALOG_QUESTION
);
497 vlc_mutex_unlock(&p_provider
->lock
);
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
,
504 vlc_mutex_unlock(&p_provider
->lock
);
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
)
517 assert(p_obj
!= NULL
&& psz_fmt
!= NULL
&& psz_title
!= NULL
518 && psz_cancel
!= NULL
);
520 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, true);
521 if (p_provider
== NULL
)
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
)
531 struct dialog_answer answer
;
532 i_ret
= dialog_wait(p_provider
, p_id
, VLC_DIALOG_QUESTION
, &answer
);
536 if (answer
.u
.question
.i_action
!= 1 && answer
.u
.question
.i_action
!= 2)
539 return answer
.u
.question
.i_action
;
542 #undef vlc_dialog_wait_question
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
, ...)
550 assert(psz_fmt
!= NULL
);
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
,
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
)
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
)
571 vlc_mutex_unlock(&p_provider
->lock
);
576 if (vasprintf(&psz_text
, psz_fmt
, ap
) == -1)
578 vlc_mutex_unlock(&p_provider
->lock
);
582 vlc_dialog_id
*p_id
= dialog_add_locked(p_provider
, VLC_DIALOG_PROGRESS
);
586 vlc_mutex_unlock(&p_provider
->lock
);
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
,
594 vlc_mutex_unlock(&p_provider
->lock
);
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
,
606 assert(p_obj
!= NULL
&& psz_title
!= NULL
&& psz_fmt
!= NULL
);
608 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, true);
609 if (p_provider
== NULL
)
612 int i_ret
= display_progress_va(p_provider
, &p_id
, b_indeterminate
,
613 f_position
, psz_cancel
, psz_title
, psz_fmt
,
615 return i_ret
== VLC_SUCCESS
? p_id
: NULL
;
618 #undef vlc_dialog_display_progress
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
, ...)
624 assert(psz_fmt
!= NULL
);
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
);
635 dialog_update_progress(vlc_object_t
*p_obj
, vlc_dialog_id
*p_id
, float f_value
,
638 assert(p_obj
!= NULL
&& p_id
!= NULL
);
639 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, false);
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
))
645 vlc_mutex_unlock(&p_provider
->lock
);
650 if (p_id
->b_progress_indeterminate
)
653 if (psz_text
!= NULL
)
655 free(p_id
->psz_progress_text
);
656 p_id
->psz_progress_text
= psz_text
;
658 p_provider
->cbs
.pf_update_progress(p_provider
->p_cbs_data
, p_id
, f_value
,
659 p_id
->psz_progress_text
);
661 vlc_mutex_unlock(&p_provider
->lock
);
665 #undef vlc_dialog_update_progress
667 vlc_dialog_update_progress(vlc_object_t
*p_obj
, vlc_dialog_id
*p_id
,
670 return dialog_update_progress(p_obj
, p_id
, f_value
, NULL
);
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
,
678 assert(psz_fmt
!= NULL
);
681 if (vasprintf(&psz_text
, psz_fmt
, ap
) == -1)
683 return dialog_update_progress(p_obj
, p_id
, f_value
, psz_text
);
686 #undef vlc_dialog_update_progress_text
688 vlc_dialog_update_progress_text(vlc_object_t
*p_obj
, vlc_dialog_id
*p_id
,
689 float f_value
, const char *psz_fmt
, ...)
691 assert(psz_fmt
!= NULL
);
693 va_start(ap
, psz_fmt
);
694 int i_ret
= vlc_dialog_update_progress_text_va(p_obj
, p_id
, f_value
,
700 #undef vlc_dialog_release
702 vlc_dialog_release(vlc_object_t
*p_obj
, vlc_dialog_id
*p_id
)
704 assert(p_obj
!= NULL
&& p_id
!= NULL
);
705 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, false);
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
);
713 #undef vlc_dialog_is_cancelled
715 vlc_dialog_is_cancelled(vlc_object_t
*p_obj
, vlc_dialog_id
*p_id
)
718 assert(p_id
!= NULL
);
720 vlc_mutex_lock(&p_id
->lock
);
721 bool b_cancelled
= p_id
->b_cancelled
;
722 vlc_mutex_unlock(&p_id
->lock
);
727 vlc_dialog_id_set_context(vlc_dialog_id
*p_id
, void *p_context
)
729 vlc_mutex_lock(&p_id
->lock
);
730 p_id
->p_context
= p_context
;
731 vlc_mutex_unlock(&p_id
->lock
);
735 vlc_dialog_id_get_context(vlc_dialog_id
*p_id
)
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
);
745 dialog_id_post(vlc_dialog_id
*p_id
, struct dialog_answer
*p_answer
)
747 vlc_mutex_lock(&p_id
->lock
);
748 if (p_answer
== NULL
)
750 p_id
->b_cancelled
= true;
754 p_id
->answer
= *p_answer
;
755 p_id
->b_answered
= true;
758 if (p_id
->i_refcount
> 0)
760 vlc_cond_signal(&p_id
->wait
);
761 vlc_mutex_unlock(&p_id
->lock
);
765 vlc_mutex_unlock(&p_id
->lock
);
766 dialog_id_release(p_id
);
772 vlc_dialog_id_post_login(vlc_dialog_id
*p_id
, const char *psz_username
,
773 const char *psz_password
, bool b_store
)
775 assert(p_id
!= NULL
&& psz_username
!= NULL
&& psz_password
!= NULL
);
777 struct dialog_answer answer
= {
778 .i_type
= VLC_DIALOG_LOGIN
,
781 .psz_username
= strdup(psz_username
),
782 .psz_password
= strdup(psz_password
),
785 if (answer
.u
.login
.psz_username
== NULL
786 || answer
.u
.login
.psz_password
== NULL
)
788 free(answer
.u
.login
.psz_username
);
789 free(answer
.u
.login
.psz_password
);
790 dialog_id_post(p_id
, NULL
);
794 return dialog_id_post(p_id
, &answer
);
798 vlc_dialog_id_post_action(vlc_dialog_id
*p_id
, int i_action
)
800 assert(p_id
!= NULL
);
802 struct dialog_answer answer
= {
803 .i_type
= VLC_DIALOG_QUESTION
,
804 .u
.question
= { .i_action
= i_action
},
807 return dialog_id_post(p_id
, &answer
);
811 vlc_dialog_id_dismiss(vlc_dialog_id
*p_id
)
813 return dialog_id_post(p_id
, NULL
);
816 #undef vlc_dialog_provider_set_ext_callback
818 vlc_dialog_provider_set_ext_callback(vlc_object_t
*p_obj
,
819 vlc_dialog_ext_update_cb pf_update
,
822 assert(p_obj
!= NULL
);
823 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, false);
825 vlc_mutex_lock(&p_provider
->lock
);
827 p_provider
->pf_ext_update
= pf_update
;
828 p_provider
->p_ext_data
= p_data
;
830 vlc_mutex_unlock(&p_provider
->lock
);
833 #undef vlc_ext_dialog_update
835 vlc_ext_dialog_update(vlc_object_t
*p_obj
, extension_dialog_t
*p_ext_dialog
)
837 assert(p_obj
!= NULL
);
838 vlc_dialog_provider
*p_provider
= get_dialog_provider(p_obj
, false);
840 vlc_mutex_lock(&p_provider
->lock
);
841 if (p_provider
->pf_ext_update
== NULL
)
843 vlc_mutex_unlock(&p_provider
->lock
);
846 p_provider
->pf_ext_update(p_ext_dialog
, p_provider
->p_ext_data
);
847 vlc_mutex_unlock(&p_provider
->lock
);