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 );
55 static int vlclua_dialog_flush( lua_State *L );
56 static void lua_SetDialogUpdate( lua_State *L, int flag );
57 static int lua_GetDialogUpdate( lua_State *L );
58 int lua_DialogFlush( lua_State *L );
60 static int vlclua_dialog_add_button( lua_State *L );
61 static int vlclua_dialog_add_label( lua_State *L );
62 static int vlclua_dialog_add_html( lua_State *L );
63 static int vlclua_dialog_add_text_inner( lua_State *L, int );
64 static inline int vlclua_dialog_add_text_input( lua_State *L )
66 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_TEXT_FIELD );
68 static inline int vlclua_dialog_add_password( lua_State *L )
70 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_PASSWORD );
72 static inline int vlclua_dialog_add_html( lua_State *L )
74 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_HTML );
76 static int vlclua_dialog_add_check_box( lua_State *L );
77 static int vlclua_dialog_add_list( lua_State *L );
78 static int vlclua_dialog_add_dropdown( lua_State *L );
79 static int vlclua_dialog_add_image( lua_State *L );
80 static int vlclua_create_widget_inner( lua_State *L, int i_args,
81 extension_widget_t *p_widget);
83 static int vlclua_dialog_delete_widget( lua_State *L );
86 static int vlclua_widget_set_text( lua_State *L );
87 static int vlclua_widget_get_text( lua_State *L );
88 static int vlclua_widget_set_checked( lua_State *L );
89 static int vlclua_widget_get_checked( lua_State *L );
90 static int vlclua_widget_add_value( lua_State *L );
91 static int vlclua_widget_get_value( lua_State *L );
92 static int vlclua_widget_clear( lua_State *L );
93 static int vlclua_widget_get_selection( lua_State *L );
96 static void AddWidget( extension_dialog_t *p_dialog,
97 extension_widget_t *p_widget );
98 static int DeleteWidget( extension_dialog_t *p_dialog,
99 extension_widget_t *p_widget );
101 static const luaL_Reg vlclua_dialog_reg[] = {
102 { "show", vlclua_dialog_show },
103 { "hide", vlclua_dialog_hide },
104 { "close", vlclua_dialog_delete },
105 { "flush", vlclua_dialog_flush },
107 { "add_button", vlclua_dialog_add_button },
108 { "add_label", vlclua_dialog_add_label },
109 { "add_html", vlclua_dialog_add_html },
110 { "add_text_input", vlclua_dialog_add_text_input },
111 { "add_password", vlclua_dialog_add_password },
112 { "add_check_box", vlclua_dialog_add_check_box },
113 { "add_dropdown", vlclua_dialog_add_dropdown },
114 { "add_list", vlclua_dialog_add_list },
115 { "add_image", vlclua_dialog_add_image },
117 { "del_widget", vlclua_dialog_delete_widget },
121 static const luaL_Reg vlclua_widget_reg[] = {
122 { "set_text", vlclua_widget_set_text },
123 { "get_text", vlclua_widget_get_text },
124 { "set_checked", vlclua_widget_set_checked },
125 { "get_checked", vlclua_widget_get_checked },
126 { "add_value", vlclua_widget_add_value },
127 { "get_value", vlclua_widget_get_value },
128 { "clear", vlclua_widget_clear },
129 { "get_selection", vlclua_widget_get_selection },
133 /** Private static variable used for the registry index */
134 static const char key_opaque = 'A',
138 * Open dialog library for Lua
140 * @param opaque Object associated to this lua state
141 * @note opaque will be p_ext for extensions, p_sd for service discoveries
143 void luaopen_dialog( lua_State *L, void *opaque )
145 lua_getglobal( L, "vlc" );
146 lua_pushcfunction( L, vlclua_dialog_create );
147 lua_setfield( L, -2, "dialog" );
149 /* Add a private pointer (opaque) in the registry
150 * The &key pointer is used to have a unique entry in the registry
152 lua_pushlightuserdata( L, (void*) &key_opaque );
153 lua_pushlightuserdata( L, opaque );
154 lua_settable( L, LUA_REGISTRYINDEX );
156 /* Add private data: dialog update flag */
157 lua_SetDialogUpdate( L, 0 );
160 static int vlclua_dialog_create( lua_State *L )
162 if( !lua_isstring( L, 1 ) )
163 return luaL_error( L, "vlc.dialog() usage: (title)" );
164 const char *psz_title = luaL_checkstring( L, 1 );
166 vlc_object_t *p_this = vlclua_get_this( L );
168 extension_dialog_t *p_dlg = calloc( 1, sizeof( extension_dialog_t ) );
170 return 0; // luaL_error( L, "Out Of Memory" );
172 lua_getglobal( L, "vlc" );
173 lua_getfield( L, -1, "__dialog" );
174 if( lua_topointer( L, lua_gettop( L ) ) != NULL )
177 return luaL_error( L, "Only one dialog allowed per extension!" );
180 p_dlg->p_object = p_this;
181 p_dlg->psz_title = strdup( psz_title );
182 p_dlg->b_kill = false;
183 ARRAY_INIT( p_dlg->widgets );
185 /* Read the opaque value stored while loading the dialog library */
186 lua_pushlightuserdata( L, (void*) &key_opaque );
187 lua_gettable( L, LUA_REGISTRYINDEX );
188 p_dlg->p_sys = (void*) lua_topointer( L, -1 ); // "const" discarded
191 vlc_mutex_init( &p_dlg->lock );
192 vlc_cond_init( &p_dlg->cond );
194 /** @todo Use the registry instead of __dialog,
195 so that the user can't tamper with it */
197 lua_getglobal( L, "vlc" );
198 lua_pushlightuserdata( L, p_dlg );
199 lua_setfield( L, -2, "__dialog" );
202 extension_dialog_t **pp_dlg = lua_newuserdata( L, sizeof( void* ) );
205 if( luaL_newmetatable( L, "dialog" ) )
208 luaL_register( L, NULL, vlclua_dialog_reg );
209 lua_setfield( L, -2, "__index" );
210 lua_pushcfunction( L, vlclua_dialog_delete );
211 lua_setfield( L, -2, "__gc" );
214 lua_setmetatable( L, -2 );
216 msg_Dbg( p_this, "Creating dialog '%s'", psz_title );
217 lua_SetDialogUpdate( L, 0 );
222 static int vlclua_dialog_delete( lua_State *L )
224 vlc_object_t *p_mgr = vlclua_get_this( L );
226 /* Get dialog descriptor */
227 extension_dialog_t **pp_dlg =
228 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
230 if( !pp_dlg || !*pp_dlg )
231 return luaL_error( L, "Can't get pointer to dialog" );
233 extension_dialog_t *p_dlg = *pp_dlg;
236 /* Remove private __dialog field */
237 lua_getglobal( L, "vlc" );
239 lua_setfield( L, -2, "__dialog" );
241 assert( !p_dlg->b_kill );
243 /* Immediately deleting the dialog */
244 msg_Dbg( p_mgr, "Deleting dialog '%s'", p_dlg->psz_title );
245 p_dlg->b_kill = true;
246 lua_SetDialogUpdate( L, 0 ); // Reset the update flag
247 dialog_ExtensionUpdate( p_mgr, p_dlg );
249 /* After dialog_ExtensionUpdate, the UI thread must take the lock asap and
250 * then signal us when it's done deleting the dialog.
252 msg_Dbg( p_mgr, "Waiting for the dialog to be deleted..." );
253 vlc_mutex_lock( &p_dlg->lock );
254 while( p_dlg->p_sys_intf != NULL )
256 vlc_cond_wait( &p_dlg->cond, &p_dlg->lock );
258 vlc_mutex_unlock( &p_dlg->lock );
260 free( p_dlg->psz_title );
261 p_dlg->psz_title = NULL;
263 /* Destroy widgets */
264 extension_widget_t *p_widget;
265 FOREACH_ARRAY( p_widget, p_dlg->widgets )
269 free( p_widget->psz_text );
272 struct extension_widget_value_t *p_value, *p_next;
273 for( p_value = p_widget->p_values; p_value != NULL; p_value = p_next )
275 p_next = p_value->p_next;
276 free( p_value->psz_text );
282 ARRAY_RESET( p_dlg->widgets );
284 /* Note: At this point, the UI must not use these resources */
285 vlc_mutex_destroy( &p_dlg->lock );
286 vlc_cond_destroy( &p_dlg->cond );
291 /** Show the dialog */
292 static int vlclua_dialog_show( lua_State *L )
294 extension_dialog_t **pp_dlg =
295 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
296 if( !pp_dlg || !*pp_dlg )
297 return luaL_error( L, "Can't get pointer to dialog" );
298 extension_dialog_t *p_dlg = *pp_dlg;
300 p_dlg->b_hide = false;
301 lua_SetDialogUpdate( L, 1 );
306 /** Hide the dialog */
307 static int vlclua_dialog_hide( lua_State *L )
309 extension_dialog_t **pp_dlg =
310 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
311 if( !pp_dlg || !*pp_dlg )
312 return luaL_error( L, "Can't get pointer to dialog" );
313 extension_dialog_t *p_dlg = *pp_dlg;
315 p_dlg->b_hide = true;
316 lua_SetDialogUpdate( L, 1 );
322 /** Flush the dialog */
323 static int vlclua_dialog_flush( lua_State *L )
325 vlc_object_t *p_mgr = vlclua_get_this( L );
327 extension_dialog_t **pp_dlg =
328 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
329 if( !pp_dlg || !*pp_dlg )
330 return luaL_error( L, "Can't get pointer to dialog" );
331 extension_dialog_t *p_dlg = *pp_dlg;
333 // Updating dialog immediately
334 dialog_ExtensionUpdate( p_mgr, p_dlg );
337 lua_SetDialogUpdate( L, 0 );
342 static void lua_SetDialogUpdate( lua_State *L, int flag )
344 /* Set entry in the Lua registry */
345 lua_pushlightuserdata( L, (void*) &key_update );
346 lua_pushinteger( L, flag );
347 lua_settable( L, LUA_REGISTRYINDEX );
350 static int lua_GetDialogUpdate( lua_State *L )
352 /* Read entry in the Lua registry */
353 lua_pushlightuserdata( L, (void*) &key_update );
354 lua_gettable( L, LUA_REGISTRYINDEX );
355 return luaL_checkinteger( L, -1 );
358 /** Manually flush a dialog
359 * This can be called after a lua_pcall
360 * @return SUCCESS if there is no dialog or the update was successful
361 * @todo If there can be multiple dialogs, this function will have to
362 * be fixed (lookup for dialog)
364 int lua_DialogFlush( lua_State *L )
366 lua_getglobal( L, "vlc" );
367 lua_getfield( L, -1, "__dialog" );
368 extension_dialog_t *p_dlg = ( extension_dialog_t* )lua_topointer( L, -1 );
373 int i_ret = VLC_SUCCESS;
374 if( lua_GetDialogUpdate( L ) )
376 i_ret = dialog_ExtensionUpdate( vlclua_get_this( L ), p_dlg );
377 lua_SetDialogUpdate( L, 0 );
384 * Create a button: add_button
385 * Arguments: text, function (as string)
388 static int vlclua_dialog_add_button( lua_State *L )
390 /* Verify arguments */
391 if( !lua_isstring( L, 2 ) || !lua_isfunction( L, 3 ) )
392 return luaL_error( L, "dialog:add_button usage: (text, func)" );
394 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
395 p_widget->type = EXTENSION_WIDGET_BUTTON;
396 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
398 lua_pushlightuserdata( L, p_widget );
400 lua_settable( L, LUA_REGISTRYINDEX );
401 p_widget->p_sys = NULL;
403 return vlclua_create_widget_inner( L, 2, p_widget );
407 * Create a text label: add_label
411 static int vlclua_dialog_add_label( lua_State *L )
413 /* Verify arguments */
414 if( !lua_isstring( L, 2 ) )
415 return luaL_error( L, "dialog:add_label usage: (text)" );
416 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
417 p_widget->type = EXTENSION_WIDGET_LABEL;
418 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
420 return vlclua_create_widget_inner( L, 1, p_widget );
424 * Create a text area: add_html, add_text_input, add_password
425 * Arguments: text (may be nil)
426 * Qt: QLineEdit (Text/Password) or QTextArea (HTML)
428 static int vlclua_dialog_add_text_inner( lua_State *L, int i_type )
430 /* Verify arguments */
431 if( !lua_isstring( L, 2 ) && !lua_isnil( L, 2 ) )
432 return luaL_error( L, "dialog:add_text_input usage: (text = nil)" );
434 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
435 p_widget->type = i_type;
436 if( !lua_isnil( L, 2 ) )
437 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
439 return vlclua_create_widget_inner( L, 1, p_widget );
443 * Create a checkable box: add_check_box
444 * Arguments: text, checked (as bool)
447 static int vlclua_dialog_add_check_box( lua_State *L )
449 /* Verify arguments */
450 if( !lua_isstring( L, 2 ) )
451 return luaL_error( L, "dialog:add_check_box usage: (text, checked)" );
453 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
454 p_widget->type = EXTENSION_WIDGET_CHECK_BOX;
455 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
456 p_widget->b_checked = lua_toboolean( L, 3 );
458 return vlclua_create_widget_inner( L, 2, p_widget );
462 * Create a drop-down list (non editable)
465 * @todo make it editable?
467 static int vlclua_dialog_add_dropdown( lua_State *L )
469 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
470 p_widget->type = EXTENSION_WIDGET_DROPDOWN;
472 return vlclua_create_widget_inner( L, 0, p_widget );
476 * Create a list panel (multiple selection)
480 static int vlclua_dialog_add_list( lua_State *L )
482 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
483 p_widget->type = EXTENSION_WIDGET_LIST;
485 return vlclua_create_widget_inner( L, 0, p_widget );
489 * Create an image label
491 * Qt: QLabel with setPixmap( QPixmap& )
493 static int vlclua_dialog_add_image( lua_State *L )
495 /* Verify arguments */
496 if( !lua_isstring( L, 2 ) )
497 return luaL_error( L, "dialog:add_image usage: (filename)" );
499 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
500 p_widget->type = EXTENSION_WIDGET_IMAGE;
501 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
503 return vlclua_create_widget_inner( L, 1, p_widget );
507 * Internal helper to finalize the creation of a widget
509 * @param i_args Number of arguments before "row" (0 or more)
510 * @param p_widget The widget to add
512 static int vlclua_create_widget_inner( lua_State *L, int i_args,
513 extension_widget_t *p_widget )
515 int arg = i_args + 2;
518 extension_dialog_t **pp_dlg =
519 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
520 if( !pp_dlg || !*pp_dlg )
521 return luaL_error( L, "Can't get pointer to dialog" );
522 extension_dialog_t *p_dlg = *pp_dlg;
524 /* Set parent dialog */
525 p_widget->p_dialog = p_dlg;
527 /* Set common arguments: col, row, hspan, vspan, width, height */
528 if( lua_isnumber( L, arg ) )
529 p_widget->i_column = luaL_checkinteger( L, arg );
530 else goto end_of_args;
531 if( lua_isnumber( L, ++arg ) )
532 p_widget->i_row = luaL_checkinteger( L, arg );
533 else goto end_of_args;
534 if( lua_isnumber( L, ++arg ) )
535 p_widget->i_horiz_span = luaL_checkinteger( L, arg );
536 else goto end_of_args;
537 if( lua_isnumber( L, ++arg ) )
538 p_widget->i_vert_span = luaL_checkinteger( L, arg );
539 else goto end_of_args;
540 if( lua_isnumber( L, ++arg ) )
541 p_widget->i_width = luaL_checkinteger( L, arg );
542 else goto end_of_args;
543 if( lua_isnumber( L, ++arg ) )
544 p_widget->i_height = luaL_checkinteger( L, arg );
545 else goto end_of_args;
548 vlc_mutex_lock( &p_dlg->lock );
550 /* Add the widget to the dialog descriptor */
551 AddWidget( p_dlg, p_widget );
553 vlc_mutex_unlock( &p_dlg->lock );
555 /* Create meta table */
556 extension_widget_t **pp_widget = lua_newuserdata( L, sizeof( void* ) );
557 *pp_widget = p_widget;
558 if( luaL_newmetatable( L, "widget" ) )
561 luaL_register( L, NULL, vlclua_widget_reg );
562 lua_setfield( L, -2, "__index" );
564 lua_setmetatable( L, -2 );
566 lua_SetDialogUpdate( L, 1 );
571 static int vlclua_widget_set_text( lua_State *L )
574 extension_widget_t **pp_widget =
575 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
576 if( !pp_widget || !*pp_widget )
577 return luaL_error( L, "Can't get pointer to widget" );
578 extension_widget_t *p_widget = *pp_widget;
580 /* Verify arguments */
581 if( !lua_isstring( L, 2 ) )
582 return luaL_error( L, "widget:set_text usage: (text)" );
584 /* Verify widget type */
585 switch( p_widget->type )
587 case EXTENSION_WIDGET_LABEL:
588 case EXTENSION_WIDGET_BUTTON:
589 case EXTENSION_WIDGET_HTML:
590 case EXTENSION_WIDGET_TEXT_FIELD:
591 case EXTENSION_WIDGET_PASSWORD:
592 case EXTENSION_WIDGET_DROPDOWN:
593 case EXTENSION_WIDGET_CHECK_BOX:
595 case EXTENSION_WIDGET_LIST:
596 case EXTENSION_WIDGET_IMAGE:
598 return luaL_error( L, "method set_text not valid for this widget" );
601 vlc_mutex_lock( &p_widget->p_dialog->lock );
604 p_widget->b_update = true;
605 free( p_widget->psz_text );
606 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
608 vlc_mutex_unlock( &p_widget->p_dialog->lock );
610 lua_SetDialogUpdate( L, 1 );
615 static int vlclua_widget_get_text( lua_State *L )
618 extension_widget_t **pp_widget =
619 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
620 if( !pp_widget || !*pp_widget )
621 return luaL_error( L, "Can't get pointer to widget" );
622 extension_widget_t *p_widget = *pp_widget;
624 /* Verify widget type */
625 switch( p_widget->type )
627 case EXTENSION_WIDGET_LABEL:
628 case EXTENSION_WIDGET_BUTTON:
629 case EXTENSION_WIDGET_HTML:
630 case EXTENSION_WIDGET_TEXT_FIELD:
631 case EXTENSION_WIDGET_PASSWORD:
632 case EXTENSION_WIDGET_DROPDOWN:
633 case EXTENSION_WIDGET_CHECK_BOX:
635 case EXTENSION_WIDGET_LIST:
636 case EXTENSION_WIDGET_IMAGE:
638 return luaL_error( L, "method get_text not valid for this widget" );
641 extension_dialog_t *p_dlg = p_widget->p_dialog;
642 vlc_mutex_lock( &p_dlg->lock );
644 char *psz_text = NULL;
645 if( p_widget->psz_text )
646 psz_text = strdup( p_widget->psz_text );
647 vlc_mutex_unlock( &p_dlg->lock );
649 lua_pushstring( L, psz_text );
655 static int vlclua_widget_get_checked( lua_State *L )
658 extension_widget_t **pp_widget =
659 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
660 if( !pp_widget || !*pp_widget )
661 return luaL_error( L, "Can't get pointer to widget" );
662 extension_widget_t *p_widget = *pp_widget;
664 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
665 return luaL_error( L, "method get_checked not valid for this widget" );
667 vlc_mutex_lock( &p_widget->p_dialog->lock );
668 lua_pushboolean( L, p_widget->b_checked );
669 vlc_mutex_unlock( &p_widget->p_dialog->lock );
674 static int vlclua_widget_add_value( lua_State *L )
677 extension_widget_t **pp_widget =
678 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
679 if( !pp_widget || !*pp_widget )
680 return luaL_error( L, "Can't get pointer to widget" );
681 extension_widget_t *p_widget = *pp_widget;
683 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
684 && p_widget->type != EXTENSION_WIDGET_LIST )
685 return luaL_error( L, "method add_value not valid for this widget" );
687 if( !lua_isstring( L, 2 ) )
688 return luaL_error( L, "widget:add_value usage: (text, id = 0)" );
690 struct extension_widget_value_t *p_value,
691 *p_new_value = calloc( 1, sizeof( struct extension_widget_value_t ) );
692 p_new_value->psz_text = strdup( luaL_checkstring( L, 2 ) );
693 p_new_value->i_id = lua_tointeger( L, 3 );
695 vlc_mutex_lock( &p_widget->p_dialog->lock );
697 if( !p_widget->p_values )
699 p_widget->p_values = p_new_value;
703 for( p_value = p_widget->p_values;
704 p_value->p_next != NULL;
705 p_value = p_value->p_next )
706 { /* Do nothing, iterate to find the end */ }
707 p_value->p_next = p_new_value;
710 p_widget->b_update = true;
711 vlc_mutex_unlock( &p_widget->p_dialog->lock );
713 lua_SetDialogUpdate( L, 1 );
718 static int vlclua_widget_get_value( 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 return luaL_error( L, "method get_value not valid for this widget" );
730 vlc_mutex_lock( &p_widget->p_dialog->lock );
732 struct extension_widget_value_t *p_value;
733 for( p_value = p_widget->p_values;
735 p_value = p_value->p_next )
737 if( p_value->b_selected )
739 lua_pushinteger( L, p_value->i_id );
740 lua_pushstring( L, p_value->psz_text );
741 vlc_mutex_unlock( &p_widget->p_dialog->lock );
746 vlc_mutex_unlock( &p_widget->p_dialog->lock );
748 lua_pushinteger( L, -1 );
753 static int vlclua_widget_clear( lua_State *L )
756 extension_widget_t **pp_widget =
757 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
758 if( !pp_widget || !*pp_widget )
759 return luaL_error( L, "Can't get pointer to widget" );
760 extension_widget_t *p_widget = *pp_widget;
762 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
763 && p_widget->type != EXTENSION_WIDGET_LIST )
764 return luaL_error( L, "method clear not valid for this widget" );
766 struct extension_widget_value_t *p_value, *p_next;
768 vlc_mutex_lock( &p_widget->p_dialog->lock );
770 for( p_value = p_widget->p_values;
774 p_next = p_value->p_next;
775 free( p_value->psz_text );
779 p_widget->p_values = NULL;
780 p_widget->b_update = true;
782 vlc_mutex_unlock( &p_widget->p_dialog->lock );
784 lua_SetDialogUpdate( L, 1 );
789 static int vlclua_widget_get_selection( lua_State *L )
792 extension_widget_t **pp_widget =
793 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
794 if( !pp_widget || !*pp_widget )
795 return luaL_error( L, "Can't get pointer to widget" );
796 extension_widget_t *p_widget = *pp_widget;
798 if( p_widget->type != EXTENSION_WIDGET_LIST )
799 return luaL_error( L, "method get_selection not valid for this widget" );
801 /* Create empty table */
804 vlc_mutex_lock( &p_widget->p_dialog->lock );
806 struct extension_widget_value_t *p_value;
807 for( p_value = p_widget->p_values;
809 p_value = p_value->p_next )
811 if( p_value->b_selected )
813 lua_pushinteger( L, p_value->i_id );
814 lua_pushstring( L, p_value->psz_text );
815 lua_settable( L, -3 );
819 vlc_mutex_unlock( &p_widget->p_dialog->lock );
825 static int vlclua_widget_set_checked( lua_State *L )
828 extension_widget_t **pp_widget =
829 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
830 if( !pp_widget || !*pp_widget )
831 return luaL_error( L, "Can't get pointer to widget" );
832 extension_widget_t *p_widget = *pp_widget;
834 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
835 return luaL_error( L, "method set_checked not valid for this widget" );
837 /* Verify arguments */
838 if( !lua_isboolean( L, 2 ) )
839 return luaL_error( L, "widget:set_checked usage: (bool)" );
841 vlc_mutex_lock( &p_widget->p_dialog->lock );
843 bool b_old_check = p_widget->b_checked;
844 p_widget->b_checked = lua_toboolean( L, 2 );
846 vlc_mutex_unlock( &p_widget->p_dialog->lock );
848 if( b_old_check != p_widget->b_checked )
850 /* Signal interface of the change */
851 p_widget->b_update = true;
852 lua_SetDialogUpdate( L, 1 );
859 * Delete a widget from a dialog
860 * Remove it from the list once it has been safely destroyed by the interface
861 * @note This will always flush the dialog
863 static int vlclua_dialog_delete_widget( lua_State *L )
866 extension_dialog_t **pp_dlg =
867 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
868 if( !pp_dlg || !*pp_dlg )
869 return luaL_error( L, "Can't get pointer to dialog" );
870 extension_dialog_t *p_dlg = *pp_dlg;
873 if( !lua_isuserdata( L, 2 ) )
874 return luaL_error( L, "Argument to del_widget is not a widget" );
877 extension_widget_t **pp_widget =
878 (extension_widget_t **) luaL_checkudata( L, 2, "widget" );
879 if( !pp_widget || !*pp_widget )
880 return luaL_error( L, "Can't get pointer to widget" );
881 extension_widget_t *p_widget = *pp_widget;
885 if( p_widget->type == EXTENSION_WIDGET_BUTTON )
887 /* Remove button action from registry */
888 lua_pushlightuserdata( L, p_widget );
890 lua_settable( L, LUA_REGISTRYINDEX );
893 vlc_object_t *p_mgr = vlclua_get_this( L );
895 p_widget->b_kill = true;
897 lua_SetDialogUpdate( L, 0 ); // Reset update flag
898 int i_ret = dialog_ExtensionUpdate( p_mgr, p_dlg );
900 if( i_ret != VLC_SUCCESS )
902 return luaL_error( L, "Could not delete widget" );
905 vlc_mutex_lock( &p_dlg->lock );
907 /* Same remarks as for dialog delete.
908 * If the dialog is deleted or about to be deleted, then there is no
909 * need to wait on this particular widget that already doesn't exist
910 * anymore in the UI */
911 while( p_widget->p_sys_intf != NULL && !p_dlg->b_kill
912 && p_dlg->p_sys_intf != NULL )
914 vlc_cond_wait( &p_dlg->cond, &p_dlg->lock );
917 i_ret = DeleteWidget( p_dlg, p_widget );
919 vlc_mutex_unlock( &p_dlg->lock );
921 if( i_ret != VLC_SUCCESS )
923 return luaL_error( L, "Could not remove widget from list" );
931 * Below this line, no Lua specific code.
937 * Add a widget to the widget list of a dialog
938 * @note Must be entered with lock on dialog
940 static void AddWidget( extension_dialog_t *p_dialog,
941 extension_widget_t *p_widget )
943 ARRAY_APPEND( p_dialog->widgets, p_widget );
947 * Remove a widget from the widget list of a dialog
948 * @note The widget MUST have been safely killed before
949 * @note Must be entered with lock on dialog
951 static int DeleteWidget( extension_dialog_t *p_dialog,
952 extension_widget_t *p_widget )
956 extension_widget_t *p_iter;
957 FOREACH_ARRAY( p_iter, p_dialog->widgets )
960 if( p_iter == p_widget )
971 ARRAY_REMOVE( p_dialog->widgets, pos );
973 /* Now free the data */
974 free( p_widget->p_sys );
975 struct extension_widget_value_t *p_value = p_widget->p_values;
978 free( p_value->psz_text );
979 struct extension_widget_value_t *old = p_value;
980 p_value = p_value->p_next;
983 free( p_widget->psz_text );