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_flush( lua_State *L );
54 static void lua_SetDialogUpdate( lua_State *L, int flag );
55 static int lua_GetDialogUpdate( lua_State *L );
56 int lua_DialogFlush( lua_State *L );
58 static int vlclua_dialog_add_button( lua_State *L );
59 static int vlclua_dialog_add_label( lua_State *L );
60 static int vlclua_dialog_add_html( lua_State *L );
61 static int vlclua_dialog_add_text_inner( lua_State *L, int );
62 static inline int vlclua_dialog_add_text_input( lua_State *L )
64 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_TEXT_FIELD );
66 static inline int vlclua_dialog_add_password( lua_State *L )
68 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_PASSWORD );
70 static inline int vlclua_dialog_add_html( lua_State *L )
72 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_HTML );
74 static int vlclua_dialog_add_check_box( lua_State *L );
75 static int vlclua_dialog_add_list( lua_State *L );
76 static int vlclua_dialog_add_dropdown( lua_State *L );
77 static int vlclua_dialog_add_image( lua_State *L );
78 static int vlclua_create_widget_inner( lua_State *L, int i_args,
79 extension_widget_t *p_widget);
81 static int vlclua_dialog_delete_widget( lua_State *L );
84 static int vlclua_widget_set_text( lua_State *L );
85 static int vlclua_widget_get_text( lua_State *L );
86 static int vlclua_widget_set_checked( lua_State *L );
87 static int vlclua_widget_get_checked( lua_State *L );
88 static int vlclua_widget_add_value( lua_State *L );
89 static int vlclua_widget_get_value( lua_State *L );
90 static int vlclua_widget_clear( lua_State *L );
91 static int vlclua_widget_get_selection( lua_State *L );
94 static void AddWidget( extension_dialog_t *p_dialog,
95 extension_widget_t *p_widget );
96 static int DeleteWidget( extension_dialog_t *p_dialog,
97 extension_widget_t *p_widget );
99 static const luaL_Reg vlclua_dialog_reg[] = {
100 { "close", vlclua_dialog_delete },
101 { "flush", vlclua_dialog_flush },
103 { "add_button", vlclua_dialog_add_button },
104 { "add_label", vlclua_dialog_add_label },
105 { "add_html", vlclua_dialog_add_html },
106 { "add_text_input", vlclua_dialog_add_text_input },
107 { "add_password", vlclua_dialog_add_password },
108 { "add_check_box", vlclua_dialog_add_check_box },
109 { "add_dropdown", vlclua_dialog_add_dropdown },
110 { "add_list", vlclua_dialog_add_list },
111 { "add_image", vlclua_dialog_add_image },
113 { "del_widget", vlclua_dialog_delete_widget },
117 static const luaL_Reg vlclua_widget_reg[] = {
118 { "set_text", vlclua_widget_set_text },
119 { "get_text", vlclua_widget_get_text },
120 { "set_checked", vlclua_widget_set_checked },
121 { "get_checked", vlclua_widget_get_checked },
122 { "add_value", vlclua_widget_add_value },
123 { "get_value", vlclua_widget_get_value },
124 { "clear", vlclua_widget_clear },
125 { "get_selection", vlclua_widget_get_selection },
129 /** Private static variable used for the registry index */
130 static const char key_opaque = 'A',
134 * Open dialog library for Lua
136 * @param opaque Object associated to this lua state
137 * @note opaque will be p_ext for extensions, p_sd for service discoveries
139 void luaopen_dialog( lua_State *L, void *opaque )
141 lua_getglobal( L, "vlc" );
142 lua_pushcfunction( L, vlclua_dialog_create );
143 lua_setfield( L, -2, "dialog" );
145 /* Add a private pointer (opaque) in the registry
146 * The &key pointer is used to have a unique entry in the registry
148 lua_pushlightuserdata( L, (void*) &key_opaque );
149 lua_pushlightuserdata( L, opaque );
150 lua_settable( L, LUA_REGISTRYINDEX );
152 /* Add private data: dialog update flag */
153 lua_SetDialogUpdate( L, 0 );
156 static int vlclua_dialog_create( lua_State *L )
158 if( !lua_isstring( L, 1 ) )
159 return luaL_error( L, "vlc.dialog() usage: (title)" );
160 const char *psz_title = luaL_checkstring( L, 1 );
162 vlc_object_t *p_this = vlclua_get_this( L );
164 extension_dialog_t *p_dlg = calloc( 1, sizeof( extension_dialog_t ) );
166 return 0; // luaL_error( L, "Out Of Memory" );
168 lua_getglobal( L, "vlc" );
169 lua_getfield( L, -1, "__dialog" );
170 if( lua_topointer( L, lua_gettop( L ) ) != NULL )
173 return luaL_error( L, "Only one dialog allowed per extension!" );
176 p_dlg->p_object = p_this;
177 p_dlg->psz_title = strdup( psz_title );
178 p_dlg->b_kill = false;
179 ARRAY_INIT( p_dlg->widgets );
181 /* Read the opaque value stored while loading the dialog library */
182 lua_pushlightuserdata( L, (void*) &key_opaque );
183 lua_gettable( L, LUA_REGISTRYINDEX );
184 p_dlg->p_sys = (void*) lua_topointer( L, -1 ); // "const" discarded
187 vlc_mutex_init( &p_dlg->lock );
188 vlc_cond_init( &p_dlg->cond );
190 /** @todo Use the registry instead of __dialog,
191 so that the user can't tamper with it */
193 lua_getglobal( L, "vlc" );
194 lua_pushlightuserdata( L, p_dlg );
195 lua_setfield( L, -2, "__dialog" );
198 extension_dialog_t **pp_dlg = lua_newuserdata( L, sizeof( void* ) );
201 if( luaL_newmetatable( L, "dialog" ) )
204 luaL_register( L, NULL, vlclua_dialog_reg );
205 lua_setfield( L, -2, "__index" );
206 lua_pushcfunction( L, vlclua_dialog_delete );
207 lua_setfield( L, -2, "__gc" );
210 lua_setmetatable( L, -2 );
212 msg_Dbg( p_this, "Creating dialog '%s'", psz_title );
213 lua_SetDialogUpdate( L, 0 );
218 static int vlclua_dialog_delete( lua_State *L )
220 vlc_object_t *p_mgr = vlclua_get_this( L );
222 /* Get dialog descriptor */
223 extension_dialog_t **pp_dlg =
224 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
226 if( !pp_dlg || !*pp_dlg )
227 return luaL_error( L, "Can't get pointer to dialog" );
229 extension_dialog_t *p_dlg = *pp_dlg;
232 /* Remove private __dialog field */
233 lua_getglobal( L, "vlc" );
235 lua_setfield( L, -2, "__dialog" );
237 assert( !p_dlg->b_kill );
239 /* Immediately deleting the dialog */
240 msg_Dbg( p_mgr, "Deleting dialog '%s'", p_dlg->psz_title );
241 p_dlg->b_kill = true;
242 lua_SetDialogUpdate( L, 0 ); // Reset the update flag
243 dialog_ExtensionUpdate( p_mgr, p_dlg );
245 /* After dialog_ExtensionUpdate, the UI thread must take the lock asap and
246 * then signal us when it's done deleting the dialog.
248 msg_Dbg( p_mgr, "Waiting for the dialog to be deleted..." );
249 vlc_mutex_lock( &p_dlg->lock );
250 while( p_dlg->p_sys_intf != NULL )
252 vlc_cond_wait( &p_dlg->cond, &p_dlg->lock );
254 vlc_mutex_unlock( &p_dlg->lock );
256 free( p_dlg->psz_title );
257 p_dlg->psz_title = NULL;
259 /* Destroy widgets */
260 extension_widget_t *p_widget;
261 FOREACH_ARRAY( p_widget, p_dlg->widgets )
265 free( p_widget->psz_text );
268 struct extension_widget_value_t *p_value, *p_next;
269 for( p_value = p_widget->p_values; p_value != NULL; p_value = p_next )
271 p_next = p_value->p_next;
272 free( p_value->psz_text );
278 ARRAY_RESET( p_dlg->widgets );
280 /* Note: At this point, the UI must not use these resources */
281 vlc_mutex_destroy( &p_dlg->lock );
282 vlc_cond_destroy( &p_dlg->cond );
288 /** Flush the dialog */
289 static int vlclua_dialog_flush( lua_State *L )
291 vlc_object_t *p_mgr = vlclua_get_this( L );
293 extension_dialog_t **pp_dlg =
294 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
295 if( !pp_dlg || !*pp_dlg )
296 return luaL_error( L, "Can't get pointer to dialog" );
297 extension_dialog_t *p_dlg = *pp_dlg;
299 // Updating dialog immediately
300 dialog_ExtensionUpdate( p_mgr, p_dlg );
303 lua_SetDialogUpdate( L, 0 );
308 static void lua_SetDialogUpdate( lua_State *L, int flag )
310 /* Set entry in the Lua registry */
311 lua_pushlightuserdata( L, (void*) &key_update );
312 lua_pushinteger( L, flag );
313 lua_settable( L, LUA_REGISTRYINDEX );
316 static int lua_GetDialogUpdate( lua_State *L )
318 /* Read entry in the Lua registry */
319 lua_pushlightuserdata( L, (void*) &key_update );
320 lua_gettable( L, LUA_REGISTRYINDEX );
321 return luaL_checkinteger( L, -1 );
324 /** Manually flush a dialog
325 * This can be called after a lua_pcall
326 * @return SUCCESS if there is no dialog or the update was successful
327 * @todo If there can be multiple dialogs, this function will have to
328 * be fixed (lookup for dialog)
330 int lua_DialogFlush( lua_State *L )
332 lua_getglobal( L, "vlc" );
333 lua_getfield( L, -1, "__dialog" );
334 extension_dialog_t *p_dlg = ( extension_dialog_t* )
335 lua_topointer( L, lua_gettop( L ) );
340 int i_ret = VLC_SUCCESS;
341 if( lua_GetDialogUpdate( L ) )
343 i_ret = dialog_ExtensionUpdate( vlclua_get_this( L ),
345 lua_SetDialogUpdate( L, 0 );
352 * Create a button: add_button
353 * Arguments: text, function (as string)
356 static int vlclua_dialog_add_button( lua_State *L )
358 /* Verify arguments */
359 if( !lua_isstring( L, 2 ) || !lua_isstring( L, 3 ) )
360 return luaL_error( L, "dialog:add_button usage: (text, func)" );
362 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
363 p_widget->type = EXTENSION_WIDGET_BUTTON;
364 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
365 p_widget->p_sys = strdup( luaL_checkstring( L, 3 ) );
367 return vlclua_create_widget_inner( L, 2, p_widget );
371 * Create a text label: add_label
375 static int vlclua_dialog_add_label( lua_State *L )
377 /* Verify arguments */
378 if( !lua_isstring( L, 2 ) )
379 return luaL_error( L, "dialog:add_label usage: (text)" );
380 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
381 p_widget->type = EXTENSION_WIDGET_LABEL;
382 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
384 return vlclua_create_widget_inner( L, 1, p_widget );
388 * Create a text area: add_html, add_text_input, add_password
389 * Arguments: text (may be nil)
390 * Qt: QLineEdit (Text/Password) or QTextArea (HTML)
392 static int vlclua_dialog_add_text_inner( lua_State *L, int i_type )
394 /* Verify arguments */
395 if( !lua_isstring( L, 2 ) && !lua_isnil( L, 2 ) )
396 return luaL_error( L, "dialog:add_text_input usage: (text = nil)" );
398 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
399 p_widget->type = i_type;
400 if( !lua_isnil( L, 2 ) )
401 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
403 return vlclua_create_widget_inner( L, 1, p_widget );
407 * Create a checkable box: add_check_box
408 * Arguments: text, checked (as bool)
411 static int vlclua_dialog_add_check_box( lua_State *L )
413 /* Verify arguments */
414 if( !lua_isstring( L, 2 ) )
415 return luaL_error( L, "dialog:add_check_box usage: (text, checked)" );
417 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
418 p_widget->type = EXTENSION_WIDGET_CHECK_BOX;
419 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
420 p_widget->b_checked = lua_toboolean( L, 3 );
422 return vlclua_create_widget_inner( L, 2, p_widget );
426 * Create a drop-down list (non editable)
429 * @todo make it editable?
431 static int vlclua_dialog_add_dropdown( lua_State *L )
433 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
434 p_widget->type = EXTENSION_WIDGET_DROPDOWN;
436 return vlclua_create_widget_inner( L, 0, p_widget );
440 * Create a list panel (multiple selection)
444 static int vlclua_dialog_add_list( lua_State *L )
446 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
447 p_widget->type = EXTENSION_WIDGET_LIST;
449 return vlclua_create_widget_inner( L, 0, p_widget );
453 * Create an image label
455 * Qt: QLabel with setPixmap( QPixmap& )
457 static int vlclua_dialog_add_image( lua_State *L )
459 /* Verify arguments */
460 if( !lua_isstring( L, 2 ) )
461 return luaL_error( L, "dialog:add_image usage: (filename)" );
463 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
464 p_widget->type = EXTENSION_WIDGET_IMAGE;
465 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
467 return vlclua_create_widget_inner( L, 1, p_widget );
471 * Internal helper to finalize the creation of a widget
473 * @param i_args Number of arguments before "row" (0 or more)
474 * @param p_widget The widget to add
476 static int vlclua_create_widget_inner( lua_State *L, int i_args,
477 extension_widget_t *p_widget )
479 int arg = i_args + 2;
482 extension_dialog_t **pp_dlg =
483 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
484 if( !pp_dlg || !*pp_dlg )
485 return luaL_error( L, "Can't get pointer to dialog" );
486 extension_dialog_t *p_dlg = *pp_dlg;
488 /* Set parent dialog */
489 p_widget->p_dialog = p_dlg;
491 /* Set common arguments: col, row, hspan, vspan, width, height */
492 if( lua_isnumber( L, arg ) )
493 p_widget->i_column = luaL_checkinteger( L, arg );
494 else goto end_of_args;
495 if( lua_isnumber( L, ++arg ) )
496 p_widget->i_row = luaL_checkinteger( L, arg );
497 else goto end_of_args;
498 if( lua_isnumber( L, ++arg ) )
499 p_widget->i_horiz_span = luaL_checkinteger( L, arg );
500 else goto end_of_args;
501 if( lua_isnumber( L, ++arg ) )
502 p_widget->i_vert_span = luaL_checkinteger( L, arg );
503 else goto end_of_args;
504 if( lua_isnumber( L, ++arg ) )
505 p_widget->i_width = luaL_checkinteger( L, arg );
506 else goto end_of_args;
507 if( lua_isnumber( L, ++arg ) )
508 p_widget->i_height = luaL_checkinteger( L, arg );
509 else goto end_of_args;
512 vlc_mutex_lock( &p_dlg->lock );
514 /* Add the widget to the dialog descriptor */
515 AddWidget( p_dlg, p_widget );
517 vlc_mutex_unlock( &p_dlg->lock );
519 /* Create meta table */
520 extension_widget_t **pp_widget = lua_newuserdata( L, sizeof( void* ) );
521 *pp_widget = p_widget;
522 if( luaL_newmetatable( L, "widget" ) )
525 luaL_register( L, NULL, vlclua_widget_reg );
526 lua_setfield( L, -2, "__index" );
528 lua_setmetatable( L, -2 );
530 lua_SetDialogUpdate( L, 1 );
535 static int vlclua_widget_set_text( lua_State *L )
538 extension_widget_t **pp_widget =
539 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
540 if( !pp_widget || !*pp_widget )
541 return luaL_error( L, "Can't get pointer to widget" );
542 extension_widget_t *p_widget = *pp_widget;
544 /* Verify arguments */
545 if( !lua_isstring( L, 2 ) )
546 return luaL_error( L, "widget:set_text usage: (text)" );
548 /* Verify widget type */
549 switch( p_widget->type )
551 case EXTENSION_WIDGET_LABEL:
552 case EXTENSION_WIDGET_BUTTON:
553 case EXTENSION_WIDGET_HTML:
554 case EXTENSION_WIDGET_TEXT_FIELD:
555 case EXTENSION_WIDGET_PASSWORD:
556 case EXTENSION_WIDGET_DROPDOWN:
557 case EXTENSION_WIDGET_CHECK_BOX:
559 case EXTENSION_WIDGET_LIST:
560 case EXTENSION_WIDGET_IMAGE:
562 vlc_mutex_unlock( &p_widget->p_dialog->lock );
563 return luaL_error( L, "method set_text not valid for this widget" );
566 vlc_mutex_lock( &p_widget->p_dialog->lock );
569 p_widget->b_update = true;
570 free( p_widget->psz_text );
571 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
573 vlc_mutex_unlock( &p_widget->p_dialog->lock );
575 lua_SetDialogUpdate( L, 1 );
580 static int vlclua_widget_get_text( lua_State *L )
583 extension_widget_t **pp_widget =
584 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
585 if( !pp_widget || !*pp_widget )
586 return luaL_error( L, "Can't get pointer to widget" );
587 extension_widget_t *p_widget = *pp_widget;
589 /* Verify widget type */
590 switch( p_widget->type )
592 case EXTENSION_WIDGET_LABEL:
593 case EXTENSION_WIDGET_BUTTON:
594 case EXTENSION_WIDGET_HTML:
595 case EXTENSION_WIDGET_TEXT_FIELD:
596 case EXTENSION_WIDGET_PASSWORD:
597 case EXTENSION_WIDGET_DROPDOWN:
598 case EXTENSION_WIDGET_CHECK_BOX:
600 case EXTENSION_WIDGET_LIST:
601 case EXTENSION_WIDGET_IMAGE:
603 return luaL_error( L, "method get_text not valid for this widget" );
606 extension_dialog_t *p_dlg = p_widget->p_dialog;
607 vlc_mutex_lock( &p_dlg->lock );
609 char *psz_text = NULL;
610 if( p_widget->psz_text )
611 psz_text = strdup( p_widget->psz_text );
612 vlc_mutex_unlock( &p_dlg->lock );
614 lua_pushstring( L, psz_text );
620 static int vlclua_widget_get_checked( lua_State *L )
623 extension_widget_t **pp_widget =
624 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
625 if( !pp_widget || !*pp_widget )
626 return luaL_error( L, "Can't get pointer to widget" );
627 extension_widget_t *p_widget = *pp_widget;
629 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
630 return luaL_error( L, "method get_checked not valid for this widget" );
632 vlc_mutex_lock( &p_widget->p_dialog->lock );
633 lua_pushboolean( L, p_widget->b_checked );
634 vlc_mutex_unlock( &p_widget->p_dialog->lock );
639 static int vlclua_widget_add_value( lua_State *L )
642 extension_widget_t **pp_widget =
643 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
644 if( !pp_widget || !*pp_widget )
645 return luaL_error( L, "Can't get pointer to widget" );
646 extension_widget_t *p_widget = *pp_widget;
648 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
649 && p_widget->type != EXTENSION_WIDGET_LIST )
650 return luaL_error( L, "method add_value not valid for this widget" );
652 if( !lua_isstring( L, 2 ) )
653 return luaL_error( L, "widget:add_value usage: (text, id = 0)" );
655 struct extension_widget_value_t *p_value,
656 *p_new_value = calloc( 1, sizeof( struct extension_widget_value_t ) );
657 p_new_value->psz_text = strdup( luaL_checkstring( L, 2 ) );
658 p_new_value->i_id = lua_tointeger( L, 3 );
660 vlc_mutex_lock( &p_widget->p_dialog->lock );
662 if( !p_widget->p_values )
664 p_widget->p_values = p_new_value;
668 for( p_value = p_widget->p_values;
669 p_value->p_next != NULL;
670 p_value = p_value->p_next )
671 { /* Do nothing, iterate to find the end */ }
672 p_value->p_next = p_new_value;
675 p_widget->b_update = true;
676 vlc_mutex_unlock( &p_widget->p_dialog->lock );
678 lua_SetDialogUpdate( L, 1 );
683 static int vlclua_widget_get_value( lua_State *L )
686 extension_widget_t **pp_widget =
687 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
688 if( !pp_widget || !*pp_widget )
689 return luaL_error( L, "Can't get pointer to widget" );
690 extension_widget_t *p_widget = *pp_widget;
692 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN )
693 return luaL_error( L, "method get_value not valid for this widget" );
695 vlc_mutex_lock( &p_widget->p_dialog->lock );
697 struct extension_widget_value_t *p_value;
698 for( p_value = p_widget->p_values;
700 p_value = p_value->p_next )
702 if( p_value->b_selected )
704 lua_pushinteger( L, p_value->i_id );
705 lua_pushstring( L, p_value->psz_text );
706 vlc_mutex_unlock( &p_widget->p_dialog->lock );
711 vlc_mutex_unlock( &p_widget->p_dialog->lock );
713 lua_pushinteger( L, -1 );
718 static int vlclua_widget_clear( lua_State *L )
721 extension_widget_t **pp_widget =
722 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
723 if( !pp_widget || !*pp_widget )
724 return luaL_error( L, "Can't get pointer to widget" );
725 extension_widget_t *p_widget = *pp_widget;
727 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
728 && p_widget->type != EXTENSION_WIDGET_LIST )
729 return luaL_error( L, "method add_value not valid for this widget" );
731 struct extension_widget_value_t *p_value, *p_next;
733 vlc_mutex_lock( &p_widget->p_dialog->lock );
735 for( p_value = p_widget->p_values;
739 p_next = p_value->p_next;
740 free( p_value->psz_text );
744 p_widget->p_values = NULL;
745 p_widget->b_update = true;
747 vlc_mutex_unlock( &p_widget->p_dialog->lock );
749 lua_SetDialogUpdate( L, 1 );
754 static int vlclua_widget_get_selection( lua_State *L )
757 extension_widget_t **pp_widget =
758 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
759 if( !pp_widget || !*pp_widget )
760 return luaL_error( L, "Can't get pointer to widget" );
761 extension_widget_t *p_widget = *pp_widget;
763 if( p_widget->type != EXTENSION_WIDGET_LIST )
764 return luaL_error( L, "method get_selection not valid for this widget" );
766 /* Create empty table */
769 vlc_mutex_lock( &p_widget->p_dialog->lock );
771 struct extension_widget_value_t *p_value;
772 for( p_value = p_widget->p_values;
774 p_value = p_value->p_next )
776 if( p_value->b_selected )
778 lua_pushinteger( L, p_value->i_id );
779 lua_pushstring( L, p_value->psz_text );
780 lua_settable( L, -3 );
784 vlc_mutex_unlock( &p_widget->p_dialog->lock );
790 static int vlclua_widget_set_checked( lua_State *L )
793 extension_widget_t **pp_widget =
794 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
795 if( !pp_widget || !*pp_widget )
796 return luaL_error( L, "Can't get pointer to widget" );
797 extension_widget_t *p_widget = *pp_widget;
799 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
800 return luaL_error( L, "method set_checked not valid for this widget" );
802 /* Verify arguments */
803 if( !lua_isboolean( L, 2 ) )
804 return luaL_error( L, "widget:set_checked usage: (bool)" );
806 vlc_mutex_lock( &p_widget->p_dialog->lock );
808 bool b_old_check = p_widget->b_checked;
809 p_widget->b_checked = lua_toboolean( L, 2 );
811 vlc_mutex_unlock( &p_widget->p_dialog->lock );
813 if( b_old_check != p_widget->b_checked )
815 /* Signal interface of the change */
816 p_widget->b_update = true;
817 lua_SetDialogUpdate( L, 1 );
824 * Delete a widget from a dialog
825 * Remove it from the list once it has been safely destroyed by the interface
826 * @note This will always flush the dialog
828 static int vlclua_dialog_delete_widget( lua_State *L )
831 extension_dialog_t **pp_dlg =
832 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
833 if( !pp_dlg || !*pp_dlg )
834 return luaL_error( L, "Can't get pointer to dialog" );
835 extension_dialog_t *p_dlg = *pp_dlg;
838 if( !lua_isuserdata( L, 2 ) )
839 return luaL_error( L, "Argument to del_widget is not a widget" );
842 extension_widget_t **pp_widget =
843 (extension_widget_t **) luaL_checkudata( L, 2, "widget" );
844 if( !pp_widget || !*pp_widget )
845 return luaL_error( L, "Can't get pointer to widget" );
846 extension_widget_t *p_widget = *pp_widget;
851 vlc_object_t *p_mgr = vlclua_get_this( L );
853 p_widget->b_kill = true;
855 lua_SetDialogUpdate( L, 0 ); // Reset update flag
856 int i_ret = dialog_ExtensionUpdate( p_mgr, p_dlg );
858 if( i_ret != VLC_SUCCESS )
860 return luaL_error( L, "Could not delete widget" );
863 vlc_mutex_lock( &p_dlg->lock );
865 /* Same remarks as for dialog delete.
866 * If the dialog is deleted or about to be deleted, then there is no
867 * need to wait on this particular widget that already doesn't exist
868 * anymore in the UI */
869 while( p_widget->p_sys_intf != NULL && !p_dlg->b_kill
870 && p_dlg->p_sys_intf != NULL )
872 vlc_cond_wait( &p_dlg->cond, &p_dlg->lock );
875 i_ret = DeleteWidget( p_dlg, p_widget );
877 vlc_mutex_unlock( &p_dlg->lock );
879 if( i_ret != VLC_SUCCESS )
881 return luaL_error( L, "Could not remove widget from list" );
889 * Below this line, no Lua specific code.
895 * Add a widget to the widget list of a dialog
896 * @note Must be entered with lock on dialog
898 static void AddWidget( extension_dialog_t *p_dialog,
899 extension_widget_t *p_widget )
901 ARRAY_APPEND( p_dialog->widgets, p_widget );
905 * Remove a widget from the widget list of a dialog
906 * @note The widget MUST have been safely killed before
907 * @note Must be entered with lock on dialog
909 static int DeleteWidget( extension_dialog_t *p_dialog,
910 extension_widget_t *p_widget )
914 extension_widget_t *p_iter;
915 FOREACH_ARRAY( p_iter, p_dialog->widgets )
918 if( p_iter == p_widget )
929 ARRAY_REMOVE( p_dialog->widgets, pos );
931 /* Now free the data */
932 free( p_widget->p_sys );
933 struct extension_widget_value_t *p_value = p_widget->p_values;
936 free( p_value->psz_text );
937 struct extension_widget_value_t *old = p_value;
938 p_value = p_value->p_next;
941 free( p_widget->psz_text );