1 /*****************************************************************************
2 * dialog.c: Functions to create interface dialogs from Lua extensions
3 *****************************************************************************
4 * Copyright (C) 2009-2010 VideoLAN and authors
7 * Authors: Jean-Philippe André < jpeg # videolan.org >
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_extensions.h>
38 #include <lua.h> /* Low level lua C API */
39 #include <lauxlib.h> /* Higher level C API */
46 /*****************************************************************************
48 *****************************************************************************/
50 /* Dialog functions */
51 static int vlclua_dialog_create( lua_State *L );
52 static int vlclua_dialog_delete( lua_State *L );
53 static int vlclua_dialog_show( lua_State *L );
54 static int vlclua_dialog_hide( lua_State *L );
56 static int vlclua_dialog_add_button( lua_State *L );
57 static int vlclua_dialog_add_label( lua_State *L );
58 static int vlclua_dialog_add_html( lua_State *L );
59 static int vlclua_dialog_add_text_inner( lua_State *L, int );
60 static inline int vlclua_dialog_add_text_input( lua_State *L )
62 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_TEXT_FIELD );
64 static inline int vlclua_dialog_add_password( lua_State *L )
66 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_PASSWORD );
68 static inline int vlclua_dialog_add_html( lua_State *L )
70 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_HTML );
72 static int vlclua_dialog_add_check_box( lua_State *L );
73 static int vlclua_dialog_add_list( lua_State *L );
74 static int vlclua_dialog_add_dropdown( lua_State *L );
75 static int vlclua_dialog_add_image( lua_State *L );
76 static int vlclua_create_widget_inner( lua_State *L, int i_args,
77 extension_widget_t *p_widget);
79 static int vlclua_dialog_delete_widget( lua_State *L );
82 static int vlclua_widget_set_text( lua_State *L );
83 static int vlclua_widget_get_text( lua_State *L );
84 static int vlclua_widget_set_checked( lua_State *L );
85 static int vlclua_widget_get_checked( lua_State *L );
86 static int vlclua_widget_add_value( lua_State *L );
87 static int vlclua_widget_get_value( lua_State *L );
88 static int vlclua_widget_clear( lua_State *L );
89 static int vlclua_widget_get_selection( lua_State *L );
92 static void AddWidget( extension_dialog_t *p_dialog,
93 extension_widget_t *p_widget );
94 static int DeleteWidget( extension_dialog_t *p_dialog,
95 extension_widget_t *p_widget );
97 static const luaL_Reg vlclua_dialog_reg[] = {
98 { "show", vlclua_dialog_show },
99 { "hide", vlclua_dialog_hide },
100 { "close", vlclua_dialog_delete },
102 { "add_button", vlclua_dialog_add_button },
103 { "add_label", vlclua_dialog_add_label },
104 { "add_html", vlclua_dialog_add_html },
105 { "add_text_input", vlclua_dialog_add_text_input },
106 { "add_password", vlclua_dialog_add_password },
107 { "add_check_box", vlclua_dialog_add_check_box },
108 { "add_dropdown", vlclua_dialog_add_dropdown },
109 { "add_list", vlclua_dialog_add_list },
110 { "add_image", vlclua_dialog_add_image },
112 { "del_widget", vlclua_dialog_delete_widget },
116 static const luaL_Reg vlclua_widget_reg[] = {
117 { "set_text", vlclua_widget_set_text },
118 { "get_text", vlclua_widget_get_text },
119 { "set_checked", vlclua_widget_set_checked },
120 { "get_checked", vlclua_widget_get_checked },
121 { "add_value", vlclua_widget_add_value },
122 { "get_value", vlclua_widget_get_value },
123 { "clear", vlclua_widget_clear },
124 { "get_selection", vlclua_widget_get_selection },
128 /** Private static variable used for the registry index */
129 static const char key_opaque = 'A';
132 * Open dialog library for Lua
134 * @param opaque Object associated to this lua state
135 * @note opaque will be p_ext for extensions, p_sd for service discoveries
137 void luaopen_dialog( lua_State *L, void *opaque )
139 lua_getglobal( L, "vlc" );
140 lua_pushcfunction( L, vlclua_dialog_create );
141 lua_setfield( L, -2, "dialog" );
143 /* Add a private pointer (opaque) in the registry
144 * The &key pointer is used to have a unique entry in the registry
146 lua_pushlightuserdata( L, (void*) &key_opaque );
147 lua_pushlightuserdata( L, opaque );
148 lua_settable( L, LUA_REGISTRYINDEX );
151 static int vlclua_dialog_create( lua_State *L )
153 if( !lua_isstring( L, 1 ) )
154 return luaL_error( L, "vlc.dialog() usage: (title)" );
155 const char *psz_title = luaL_checkstring( L, 1 );
157 vlc_object_t *p_this = vlclua_get_this( L );
159 extension_dialog_t *p_dlg = calloc( 1, sizeof( extension_dialog_t ) );
161 return 0; // luaL_error( L, "Out Of Memory" );
163 lua_getglobal( L, "vlc" );
164 lua_getfield( L, -1, "__dialog" );
165 if( lua_topointer( L, lua_gettop( L ) ) != NULL )
166 return luaL_error( L, "Only one dialog allowed per extension!" );
168 p_dlg->p_object = p_this;
169 p_dlg->psz_title = strdup( psz_title );
170 p_dlg->b_kill = false;
171 ARRAY_INIT( p_dlg->widgets );
173 /* Read the opaque value stored while loading the dialog library */
174 lua_pushlightuserdata( L, (void*) &key_opaque );
175 lua_gettable( L, LUA_REGISTRYINDEX );
176 p_dlg->p_sys = (void*) lua_topointer( L, -1 ); // "const" discarded
179 vlc_mutex_init( &p_dlg->lock );
180 vlc_cond_init( &p_dlg->cond );
182 /** @todo Use the registry instead of __dialog,
183 so that the user can't tamper with it */
185 lua_getglobal( L, "vlc" );
186 lua_pushlightuserdata( L, p_dlg );
187 lua_setfield( L, -2, "__dialog" );
190 extension_dialog_t **pp_dlg = lua_newuserdata( L, sizeof( void* ) );
193 if( luaL_newmetatable( L, "dialog" ) )
196 luaL_register( L, NULL, vlclua_dialog_reg );
197 lua_setfield( L, -2, "__index" );
198 lua_pushcfunction( L, vlclua_dialog_delete );
199 lua_setfield( L, -2, "__gc" );
202 lua_setmetatable( L, -2 );
204 msg_Dbg( p_this, "Creating dialog '%s'", psz_title );
205 int i_ret = dialog_ExtensionUpdate( p_this, p_dlg );
207 return ( i_ret == VLC_SUCCESS ) ? 1 : 0;
210 static int vlclua_dialog_delete( lua_State *L )
212 vlc_object_t *p_mgr = vlclua_get_this( L );
214 /* Get dialog descriptor */
215 extension_dialog_t **pp_dlg =
216 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
218 if( !pp_dlg || !*pp_dlg )
219 return luaL_error( L, "Can't get pointer to dialog" );
221 extension_dialog_t *p_dlg = *pp_dlg;
224 /* Remove private __dialog field */
225 lua_getglobal( L, "vlc" );
227 lua_setfield( L, -2, "__dialog" );
229 assert( !p_dlg->b_kill );
231 msg_Dbg( p_mgr, "Deleting dialog '%s'", p_dlg->psz_title );
232 p_dlg->b_kill = true;
233 dialog_ExtensionUpdate( p_mgr, p_dlg );
235 /* After dialog_ExtensionUpdate, the UI thread must take the lock asap and
236 * then signal us when it's done deleting the dialog.
238 vlc_mutex_lock( &p_dlg->lock );
239 while( p_dlg->p_sys_intf != NULL )
241 mtime_t abstime = mdate() + 1000000; // Waiting 1 second at a time
242 vlc_cond_timedwait( &p_dlg->cond, &p_dlg->lock, abstime );
244 vlc_mutex_unlock( &p_dlg->lock );
246 free( p_dlg->psz_title );
247 p_dlg->psz_title = NULL;
249 /* Destroy widgets */
250 extension_widget_t *p_widget;
251 FOREACH_ARRAY( p_widget, p_dlg->widgets )
255 free( p_widget->psz_text );
258 struct extension_widget_value_t *p_value, *p_next;
259 for( p_value = p_widget->p_values; p_value != NULL; p_value = p_next )
261 p_next = p_value->p_next;
262 free( p_value->psz_text );
268 ARRAY_RESET( p_dlg->widgets );
270 /* Note: At this point, the UI must not use these resources */
271 vlc_mutex_destroy( &p_dlg->lock );
272 vlc_cond_destroy( &p_dlg->cond );
277 /** Show the dialog */
278 static int vlclua_dialog_show( lua_State *L )
280 vlc_object_t *p_mgr = vlclua_get_this( L );
282 extension_dialog_t **pp_dlg =
283 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
284 if( !pp_dlg || !*pp_dlg )
285 return luaL_error( L, "Can't get pointer to dialog" );
286 extension_dialog_t *p_dlg = *pp_dlg;
288 p_dlg->b_hide = false;
289 dialog_ExtensionUpdate( p_mgr, p_dlg );
294 /** Hide the dialog */
295 static int vlclua_dialog_hide( lua_State *L )
297 vlc_object_t *p_mgr = vlclua_get_this( L );
299 extension_dialog_t **pp_dlg =
300 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
301 if( !pp_dlg || !*pp_dlg )
302 return luaL_error( L, "Can't get pointer to dialog" );
303 extension_dialog_t *p_dlg = *pp_dlg;
305 p_dlg->b_hide = true;
306 dialog_ExtensionUpdate( p_mgr, p_dlg );
313 * Create a button: add_button
314 * Arguments: text, function (as string)
317 static int vlclua_dialog_add_button( lua_State *L )
319 /* Verify arguments */
320 if( !lua_isstring( L, 2 ) || !lua_isstring( L, 3 ) )
321 return luaL_error( L, "dialog:add_button usage: (text, func)" );
323 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
324 p_widget->type = EXTENSION_WIDGET_BUTTON;
325 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
326 p_widget->p_sys = strdup( luaL_checkstring( L, 3 ) );
328 return vlclua_create_widget_inner( L, 2, p_widget );
332 * Create a text label: add_label
336 static int vlclua_dialog_add_label( lua_State *L )
338 /* Verify arguments */
339 if( !lua_isstring( L, 2 ) )
340 return luaL_error( L, "dialog:add_label usage: (text)" );
341 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
342 p_widget->type = EXTENSION_WIDGET_LABEL;
343 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
345 return vlclua_create_widget_inner( L, 1, p_widget );
349 * Create a text area: add_html, add_text_input, add_password
350 * Arguments: text (may be nil)
351 * Qt: QLineEdit (Text/Password) or QTextArea (HTML)
353 static int vlclua_dialog_add_text_inner( lua_State *L, int i_type )
355 /* Verify arguments */
356 if( !lua_isstring( L, 2 ) && !lua_isnil( L, 2 ) )
357 return luaL_error( L, "dialog:add_text_input usage: (text = nil)" );
359 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
360 p_widget->type = i_type;
361 if( !lua_isnil( L, 2 ) )
362 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
364 return vlclua_create_widget_inner( L, 1, p_widget );
368 * Create a checkable box: add_check_box
369 * Arguments: text, checked (as bool)
372 static int vlclua_dialog_add_check_box( lua_State *L )
374 /* Verify arguments */
375 if( !lua_isstring( L, 2 ) )
376 return luaL_error( L, "dialog:add_check_box usage: (text, checked)" );
378 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
379 p_widget->type = EXTENSION_WIDGET_CHECK_BOX;
380 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
381 p_widget->b_checked = lua_toboolean( L, 3 );
383 return vlclua_create_widget_inner( L, 2, p_widget );
387 * Create a drop-down list (non editable)
390 * @todo make it editable?
392 static int vlclua_dialog_add_dropdown( lua_State *L )
394 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
395 p_widget->type = EXTENSION_WIDGET_DROPDOWN;
397 return vlclua_create_widget_inner( L, 0, p_widget );
401 * Create a list panel (multiple selection)
405 static int vlclua_dialog_add_list( lua_State *L )
407 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
408 p_widget->type = EXTENSION_WIDGET_LIST;
410 return vlclua_create_widget_inner( L, 0, p_widget );
414 * Create an image label
416 * Qt: QLabel with setPixmap( QPixmap& )
418 static int vlclua_dialog_add_image( lua_State *L )
420 /* Verify arguments */
421 if( !lua_isstring( L, 2 ) )
422 return luaL_error( L, "dialog:add_image usage: (filename)" );
424 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
425 p_widget->type = EXTENSION_WIDGET_IMAGE;
426 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
428 return vlclua_create_widget_inner( L, 1, p_widget );
432 * Internal helper to finalize the creation of a widget
434 * @param i_args Number of arguments before "row" (0 or more)
435 * @param p_widget The widget to add
437 static int vlclua_create_widget_inner( lua_State *L, int i_args,
438 extension_widget_t *p_widget )
440 int arg = i_args + 2;
443 extension_dialog_t **pp_dlg =
444 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
445 if( !pp_dlg || !*pp_dlg )
446 return luaL_error( L, "Can't get pointer to dialog" );
447 extension_dialog_t *p_dlg = *pp_dlg;
449 /* Set parent dialog */
450 p_widget->p_dialog = p_dlg;
452 /* Set common arguments: col, row, hspan, vspan, width, height */
453 if( lua_isnumber( L, arg ) )
454 p_widget->i_column = luaL_checkinteger( L, arg );
455 else goto end_of_args;
456 if( lua_isnumber( L, ++arg ) )
457 p_widget->i_row = luaL_checkinteger( L, arg );
458 else goto end_of_args;
459 if( lua_isnumber( L, ++arg ) )
460 p_widget->i_horiz_span = luaL_checkinteger( L, arg );
461 else goto end_of_args;
462 if( lua_isnumber( L, ++arg ) )
463 p_widget->i_vert_span = luaL_checkinteger( L, arg );
464 else goto end_of_args;
465 if( lua_isnumber( L, ++arg ) )
466 p_widget->i_width = luaL_checkinteger( L, arg );
467 else goto end_of_args;
468 if( lua_isnumber( L, ++arg ) )
469 p_widget->i_height = luaL_checkinteger( L, arg );
470 else goto end_of_args;
473 vlc_mutex_lock( &p_dlg->lock );
475 /* Add the widget to the dialog descriptor */
476 AddWidget( p_dlg, p_widget );
478 vlc_mutex_unlock( &p_dlg->lock );
480 /* Create meta table */
481 extension_widget_t **pp_widget = lua_newuserdata( L, sizeof( void* ) );
482 *pp_widget = p_widget;
483 if( luaL_newmetatable( L, "widget" ) )
486 luaL_register( L, NULL, vlclua_widget_reg );
487 lua_setfield( L, -2, "__index" );
489 lua_setmetatable( L, -2 );
491 /* Signal interface */
492 vlc_object_t *p_mgr = vlclua_get_this( L );
493 int i_ret = dialog_ExtensionUpdate( p_mgr, p_dlg );
495 return ( i_ret == VLC_SUCCESS ) ? 1 : 0;
498 static int vlclua_widget_set_text( lua_State *L )
501 extension_widget_t **pp_widget =
502 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
503 if( !pp_widget || !*pp_widget )
504 return luaL_error( L, "Can't get pointer to widget" );
505 extension_widget_t *p_widget = *pp_widget;
507 /* Verify arguments */
508 if( !lua_isstring( L, 2 ) )
509 return luaL_error( L, "widget:set_text usage: (text)" );
511 /* Verify widget type */
512 switch( p_widget->type )
514 case EXTENSION_WIDGET_LABEL:
515 case EXTENSION_WIDGET_BUTTON:
516 case EXTENSION_WIDGET_HTML:
517 case EXTENSION_WIDGET_TEXT_FIELD:
518 case EXTENSION_WIDGET_PASSWORD:
519 case EXTENSION_WIDGET_DROPDOWN:
520 case EXTENSION_WIDGET_CHECK_BOX:
522 case EXTENSION_WIDGET_LIST:
523 case EXTENSION_WIDGET_IMAGE:
525 vlc_mutex_unlock( &p_widget->p_dialog->lock );
526 return luaL_error( L, "method set_text not valid for this widget" );
529 vlc_mutex_lock( &p_widget->p_dialog->lock );
532 p_widget->b_update = true;
533 free( p_widget->psz_text );
534 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
536 vlc_mutex_unlock( &p_widget->p_dialog->lock );
539 vlc_object_t *p_mgr = vlclua_get_this( L );
540 dialog_ExtensionUpdate( p_mgr, p_widget->p_dialog );
545 static int vlclua_widget_get_text( lua_State *L )
548 extension_widget_t **pp_widget =
549 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
550 if( !pp_widget || !*pp_widget )
551 return luaL_error( L, "Can't get pointer to widget" );
552 extension_widget_t *p_widget = *pp_widget;
554 /* Verify widget type */
555 switch( p_widget->type )
557 case EXTENSION_WIDGET_LABEL:
558 case EXTENSION_WIDGET_BUTTON:
559 case EXTENSION_WIDGET_HTML:
560 case EXTENSION_WIDGET_TEXT_FIELD:
561 case EXTENSION_WIDGET_PASSWORD:
562 case EXTENSION_WIDGET_DROPDOWN:
563 case EXTENSION_WIDGET_CHECK_BOX:
565 case EXTENSION_WIDGET_LIST:
566 case EXTENSION_WIDGET_IMAGE:
568 return luaL_error( L, "method get_text not valid for this widget" );
571 extension_dialog_t *p_dlg = p_widget->p_dialog;
572 vlc_mutex_lock( &p_dlg->lock );
574 char *psz_text = NULL;
575 if( p_widget->psz_text )
576 psz_text = strdup( p_widget->psz_text );
577 vlc_mutex_unlock( &p_dlg->lock );
579 lua_pushstring( L, psz_text );
585 static int vlclua_widget_get_checked( lua_State *L )
588 extension_widget_t **pp_widget =
589 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
590 if( !pp_widget || !*pp_widget )
591 return luaL_error( L, "Can't get pointer to widget" );
592 extension_widget_t *p_widget = *pp_widget;
594 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
595 return luaL_error( L, "method get_checked not valid for this widget" );
597 vlc_mutex_lock( &p_widget->p_dialog->lock );
598 lua_pushboolean( L, p_widget->b_checked );
599 vlc_mutex_unlock( &p_widget->p_dialog->lock );
604 static int vlclua_widget_add_value( lua_State *L )
607 extension_widget_t **pp_widget =
608 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
609 if( !pp_widget || !*pp_widget )
610 return luaL_error( L, "Can't get pointer to widget" );
611 extension_widget_t *p_widget = *pp_widget;
613 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
614 && p_widget->type != EXTENSION_WIDGET_LIST )
615 return luaL_error( L, "method add_value not valid for this widget" );
617 if( !lua_isstring( L, 2 ) )
618 return luaL_error( L, "widget:add_value usage: (text, id = 0)" );
620 struct extension_widget_value_t *p_value,
621 *p_new_value = calloc( 1, sizeof( struct extension_widget_value_t ) );
622 p_new_value->psz_text = strdup( luaL_checkstring( L, 2 ) );
623 p_new_value->i_id = lua_tointeger( L, 3 );
625 vlc_mutex_lock( &p_widget->p_dialog->lock );
627 if( !p_widget->p_values )
629 p_widget->p_values = p_new_value;
633 for( p_value = p_widget->p_values;
634 p_value->p_next != NULL;
635 p_value = p_value->p_next )
636 { /* Do nothing, iterate to find the end */ }
637 p_value->p_next = p_new_value;
640 p_widget->b_update = true;
641 vlc_mutex_unlock( &p_widget->p_dialog->lock );
643 vlc_object_t *p_mgr = vlclua_get_this( L );
644 dialog_ExtensionUpdate( p_mgr, p_widget->p_dialog );
649 static int vlclua_widget_get_value( lua_State *L )
652 extension_widget_t **pp_widget =
653 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
654 if( !pp_widget || !*pp_widget )
655 return luaL_error( L, "Can't get pointer to widget" );
656 extension_widget_t *p_widget = *pp_widget;
658 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN )
659 return luaL_error( L, "method get_value not valid for this widget" );
661 vlc_mutex_lock( &p_widget->p_dialog->lock );
663 struct extension_widget_value_t *p_value;
664 for( p_value = p_widget->p_values;
666 p_value = p_value->p_next )
668 if( p_value->b_selected )
670 lua_pushinteger( L, p_value->i_id );
671 lua_pushstring( L, p_value->psz_text );
672 vlc_mutex_unlock( &p_widget->p_dialog->lock );
677 vlc_mutex_unlock( &p_widget->p_dialog->lock );
679 lua_pushinteger( L, -1 );
684 static int vlclua_widget_clear( lua_State *L )
687 extension_widget_t **pp_widget =
688 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
689 if( !pp_widget || !*pp_widget )
690 return luaL_error( L, "Can't get pointer to widget" );
691 extension_widget_t *p_widget = *pp_widget;
693 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
694 && p_widget->type != EXTENSION_WIDGET_LIST )
695 return luaL_error( L, "method add_value not valid for this widget" );
697 struct extension_widget_value_t *p_value, *p_next;
699 vlc_mutex_lock( &p_widget->p_dialog->lock );
701 for( p_value = p_widget->p_values;
705 p_next = p_value->p_next;
706 free( p_value->psz_text );
710 p_widget->p_values = NULL;
711 p_widget->b_update = true;
713 vlc_mutex_unlock( &p_widget->p_dialog->lock );
715 vlc_object_t *p_mgr = vlclua_get_this( L );
716 dialog_ExtensionUpdate( p_mgr, p_widget->p_dialog );
721 static int vlclua_widget_get_selection( lua_State *L )
724 extension_widget_t **pp_widget =
725 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
726 if( !pp_widget || !*pp_widget )
727 return luaL_error( L, "Can't get pointer to widget" );
728 extension_widget_t *p_widget = *pp_widget;
730 if( p_widget->type != EXTENSION_WIDGET_LIST )
731 return luaL_error( L, "method get_selection not valid for this widget" );
733 /* Create empty table */
736 vlc_mutex_lock( &p_widget->p_dialog->lock );
738 struct extension_widget_value_t *p_value;
739 for( p_value = p_widget->p_values;
741 p_value = p_value->p_next )
743 if( p_value->b_selected )
745 lua_pushinteger( L, p_value->i_id );
746 lua_pushstring( L, p_value->psz_text );
747 lua_settable( L, -3 );
751 vlc_mutex_unlock( &p_widget->p_dialog->lock );
757 static int vlclua_widget_set_checked( lua_State *L )
760 extension_widget_t **pp_widget =
761 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
762 if( !pp_widget || !*pp_widget )
763 return luaL_error( L, "Can't get pointer to widget" );
764 extension_widget_t *p_widget = *pp_widget;
766 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
767 return luaL_error( L, "method set_checked not valid for this widget" );
769 /* Verify arguments */
770 if( !lua_isboolean( L, 2 ) )
771 return luaL_error( L, "widget:set_checked usage: (bool)" );
773 vlc_mutex_lock( &p_widget->p_dialog->lock );
775 bool b_old_check = p_widget->b_checked;
776 p_widget->b_checked = lua_toboolean( L, 2 );
778 vlc_mutex_unlock( &p_widget->p_dialog->lock );
780 if( b_old_check != p_widget->b_checked )
782 /* Signal interface of the change */
783 p_widget->b_update = true;
785 vlc_object_t *p_mgr = vlclua_get_this( L );
786 dialog_ExtensionUpdate( p_mgr, p_widget->p_dialog );
793 * Delete a widget from a dialog
794 * Remove it from the list once it has been safely destroyed by the interface
796 static int vlclua_dialog_delete_widget( lua_State *L )
799 extension_dialog_t **pp_dlg =
800 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
801 if( !pp_dlg || !*pp_dlg )
802 return luaL_error( L, "Can't get pointer to dialog" );
803 extension_dialog_t *p_dlg = *pp_dlg;
806 if( !lua_isuserdata( L, 2 ) )
807 return luaL_error( L, "Argument to del_widget is not a widget" );
810 extension_widget_t **pp_widget =
811 (extension_widget_t **) luaL_checkudata( L, 2, "widget" );
812 if( !pp_widget || !*pp_widget )
813 return luaL_error( L, "Can't get pointer to widget" );
814 extension_widget_t *p_widget = *pp_widget;
819 vlc_object_t *p_mgr = vlclua_get_this( L );
821 p_widget->b_kill = true;
823 int i_ret = dialog_ExtensionUpdate( p_mgr, p_dlg );
825 if( i_ret != VLC_SUCCESS )
827 return luaL_error( L, "Could not delete widget" );
830 vlc_mutex_lock( &p_dlg->lock );
832 /* Same remarks as for dialog delete */
833 mtime_t abstime = mdate() + 2000000;
834 if( p_widget->p_sys_intf != NULL )
835 vlc_cond_timedwait( &p_dlg->cond, &p_dlg->lock, abstime );
837 if( p_widget->p_sys_intf == NULL )
839 i_ret = DeleteWidget( p_dlg, p_widget );
841 if( i_ret != VLC_SUCCESS )
843 vlc_mutex_unlock( &p_dlg->lock );
844 return luaL_error( L, "Could not remove widget from list" );
849 msg_Warn( p_mgr, "Could not delete a widget. Leaking its descriptor." );
850 i_ret = VLC_EGENERIC;
853 vlc_mutex_unlock( &p_dlg->lock );
855 return ( i_ret == VLC_SUCCESS ) ? 1 : 0;
860 * Below this line, no Lua specific code.
866 * Add a widget to the widget list of a dialog
867 * @note Must be entered with lock on dialog
869 static void AddWidget( extension_dialog_t *p_dialog,
870 extension_widget_t *p_widget )
872 ARRAY_APPEND( p_dialog->widgets, p_widget );
876 * Remove a widget from the widget list of a dialog
877 * @note The widget MUST have been safely killed before
878 * @note Must be entered with lock on dialog
880 static int DeleteWidget( extension_dialog_t *p_dialog,
881 extension_widget_t *p_widget )
885 extension_widget_t *p_iter;
886 FOREACH_ARRAY( p_iter, p_dialog->widgets )
889 if( p_iter == p_widget )
900 ARRAY_REMOVE( p_dialog->widgets, pos );
902 /* Now free the data */
903 free( p_widget->p_sys );
904 struct extension_widget_value_t *p_value = p_widget->p_values;
907 free( p_value->psz_text );
908 struct extension_widget_value_t *old = p_value;
909 p_value = p_value->p_next;
912 free( p_widget->psz_text );