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_set_title( lua_State *L );
56 static int vlclua_dialog_update( lua_State *L );
57 static void lua_SetDialogUpdate( lua_State *L, int flag );
58 static int lua_GetDialogUpdate( lua_State *L );
59 int lua_DialogFlush( lua_State *L );
61 static int vlclua_dialog_add_button( lua_State *L );
62 static int vlclua_dialog_add_label( lua_State *L );
63 static int vlclua_dialog_add_html( lua_State *L );
64 static int vlclua_dialog_add_text_inner( lua_State *L, int );
65 static inline int vlclua_dialog_add_text_input( lua_State *L )
67 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_TEXT_FIELD );
69 static inline int vlclua_dialog_add_password( lua_State *L )
71 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_PASSWORD );
73 static inline int vlclua_dialog_add_html( lua_State *L )
75 return vlclua_dialog_add_text_inner( L, EXTENSION_WIDGET_HTML );
77 static int vlclua_dialog_add_check_box( lua_State *L );
78 static int vlclua_dialog_add_list( lua_State *L );
79 static int vlclua_dialog_add_dropdown( lua_State *L );
80 static int vlclua_dialog_add_image( lua_State *L );
81 static int vlclua_create_widget_inner( lua_State *L, int i_args,
82 extension_widget_t *p_widget);
84 static int vlclua_dialog_delete_widget( lua_State *L );
87 static int vlclua_widget_set_text( lua_State *L );
88 static int vlclua_widget_get_text( lua_State *L );
89 static int vlclua_widget_set_checked( lua_State *L );
90 static int vlclua_widget_get_checked( lua_State *L );
91 static int vlclua_widget_add_value( lua_State *L );
92 static int vlclua_widget_get_value( lua_State *L );
93 static int vlclua_widget_clear( lua_State *L );
94 static int vlclua_widget_get_selection( lua_State *L );
97 static void AddWidget( extension_dialog_t *p_dialog,
98 extension_widget_t *p_widget );
99 static int DeleteWidget( extension_dialog_t *p_dialog,
100 extension_widget_t *p_widget );
102 static const luaL_Reg vlclua_dialog_reg[] = {
103 { "show", vlclua_dialog_show },
104 { "hide", vlclua_dialog_hide },
105 { "delete", vlclua_dialog_delete },
106 { "set_title", vlclua_dialog_set_title },
107 { "update", vlclua_dialog_update },
109 { "add_button", vlclua_dialog_add_button },
110 { "add_label", vlclua_dialog_add_label },
111 { "add_html", vlclua_dialog_add_html },
112 { "add_text_input", vlclua_dialog_add_text_input },
113 { "add_password", vlclua_dialog_add_password },
114 { "add_check_box", vlclua_dialog_add_check_box },
115 { "add_dropdown", vlclua_dialog_add_dropdown },
116 { "add_list", vlclua_dialog_add_list },
117 { "add_image", vlclua_dialog_add_image },
119 { "del_widget", vlclua_dialog_delete_widget },
123 static const luaL_Reg vlclua_widget_reg[] = {
124 { "set_text", vlclua_widget_set_text },
125 { "get_text", vlclua_widget_get_text },
126 { "set_checked", vlclua_widget_set_checked },
127 { "get_checked", vlclua_widget_get_checked },
128 { "add_value", vlclua_widget_add_value },
129 { "get_value", vlclua_widget_get_value },
130 { "clear", vlclua_widget_clear },
131 { "get_selection", vlclua_widget_get_selection },
135 /** Private static variable used for the registry index */
136 static const char key_opaque = 'A',
140 * Open dialog library for Lua
142 * @param opaque Object associated to this lua state
143 * @note opaque will be p_ext for extensions, p_sd for service discoveries
145 void luaopen_dialog( lua_State *L, void *opaque )
147 lua_getglobal( L, "vlc" );
148 lua_pushcfunction( L, vlclua_dialog_create );
149 lua_setfield( L, -2, "dialog" );
151 /* Add a private pointer (opaque) in the registry
152 * The &key pointer is used to have a unique entry in the registry
154 lua_pushlightuserdata( L, (void*) &key_opaque );
155 lua_pushlightuserdata( L, opaque );
156 lua_settable( L, LUA_REGISTRYINDEX );
158 /* Add private data: dialog update flag */
159 lua_SetDialogUpdate( L, 0 );
162 static int vlclua_dialog_create( lua_State *L )
164 if( !lua_isstring( L, 1 ) )
165 return luaL_error( L, "vlc.dialog() usage: (title)" );
166 const char *psz_title = luaL_checkstring( L, 1 );
168 vlc_object_t *p_this = vlclua_get_this( L );
170 extension_dialog_t *p_dlg = calloc( 1, sizeof( extension_dialog_t ) );
172 return 0; // luaL_error( L, "Out Of Memory" );
174 lua_getglobal( L, "vlc" );
175 lua_getfield( L, -1, "__dialog" );
176 if( lua_topointer( L, lua_gettop( L ) ) != NULL )
179 return luaL_error( L, "Only one dialog allowed per extension!" );
182 p_dlg->p_object = p_this;
183 p_dlg->psz_title = strdup( psz_title );
184 p_dlg->b_kill = false;
185 ARRAY_INIT( p_dlg->widgets );
187 /* Read the opaque value stored while loading the dialog library */
188 lua_pushlightuserdata( L, (void*) &key_opaque );
189 lua_gettable( L, LUA_REGISTRYINDEX );
190 p_dlg->p_sys = (void*) lua_topointer( L, -1 ); // "const" discarded
193 vlc_mutex_init( &p_dlg->lock );
194 vlc_cond_init( &p_dlg->cond );
196 /** @todo Use the registry instead of __dialog,
197 so that the user can't tamper with it */
199 lua_getglobal( L, "vlc" );
200 lua_pushlightuserdata( L, p_dlg );
201 lua_setfield( L, -2, "__dialog" );
204 extension_dialog_t **pp_dlg = lua_newuserdata( L, sizeof( extension_dialog_t* ) );
207 if( luaL_newmetatable( L, "dialog" ) )
210 luaL_register( L, NULL, vlclua_dialog_reg );
211 lua_setfield( L, -2, "__index" );
212 lua_pushcfunction( L, vlclua_dialog_delete );
213 lua_setfield( L, -2, "__gc" );
216 lua_setmetatable( L, -2 );
218 msg_Dbg( p_this, "Creating dialog '%s'", psz_title );
219 lua_SetDialogUpdate( L, 0 );
224 static int vlclua_dialog_delete( lua_State *L )
226 vlc_object_t *p_mgr = vlclua_get_this( L );
228 /* Get dialog descriptor */
229 extension_dialog_t **pp_dlg =
230 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
232 if( !pp_dlg || !*pp_dlg )
233 return luaL_error( L, "Can't get pointer to dialog" );
235 extension_dialog_t *p_dlg = *pp_dlg;
238 /* Remove private __dialog field */
239 lua_getglobal( L, "vlc" );
241 lua_setfield( L, -2, "__dialog" );
243 assert( !p_dlg->b_kill );
245 /* Immediately deleting the dialog */
246 msg_Dbg( p_mgr, "Deleting dialog '%s'", p_dlg->psz_title );
247 p_dlg->b_kill = true;
248 lua_SetDialogUpdate( L, 0 ); // Reset the update flag
249 dialog_ExtensionUpdate( p_mgr, p_dlg );
251 /* After dialog_ExtensionUpdate, the UI thread must take the lock asap and
252 * then signal us when it's done deleting the dialog.
254 msg_Dbg( p_mgr, "Waiting for the dialog to be deleted..." );
255 vlc_mutex_lock( &p_dlg->lock );
256 while( p_dlg->p_sys_intf != NULL )
258 vlc_cond_wait( &p_dlg->cond, &p_dlg->lock );
260 vlc_mutex_unlock( &p_dlg->lock );
262 free( p_dlg->psz_title );
263 p_dlg->psz_title = NULL;
265 /* Destroy widgets */
266 extension_widget_t *p_widget;
267 FOREACH_ARRAY( p_widget, p_dlg->widgets )
271 free( p_widget->psz_text );
274 struct extension_widget_value_t *p_value, *p_next;
275 for( p_value = p_widget->p_values; p_value != NULL; p_value = p_next )
277 p_next = p_value->p_next;
278 free( p_value->psz_text );
284 ARRAY_RESET( p_dlg->widgets );
286 /* Note: At this point, the UI must not use these resources */
287 vlc_mutex_destroy( &p_dlg->lock );
288 vlc_cond_destroy( &p_dlg->cond );
293 /** Show the dialog */
294 static int vlclua_dialog_show( lua_State *L )
296 extension_dialog_t **pp_dlg =
297 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
298 if( !pp_dlg || !*pp_dlg )
299 return luaL_error( L, "Can't get pointer to dialog" );
300 extension_dialog_t *p_dlg = *pp_dlg;
302 p_dlg->b_hide = false;
303 lua_SetDialogUpdate( L, 1 );
308 /** Hide the dialog */
309 static int vlclua_dialog_hide( lua_State *L )
311 extension_dialog_t **pp_dlg =
312 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
313 if( !pp_dlg || !*pp_dlg )
314 return luaL_error( L, "Can't get pointer to dialog" );
315 extension_dialog_t *p_dlg = *pp_dlg;
317 p_dlg->b_hide = true;
318 lua_SetDialogUpdate( L, 1 );
324 /** Set the dialog's title */
325 static int vlclua_dialog_set_title( lua_State *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 vlc_mutex_lock( &p_dlg->lock );
335 const char *psz_title = luaL_checkstring( L, 2 );
336 free( p_dlg->psz_title );
337 p_dlg->psz_title = strdup( psz_title );
339 vlc_mutex_unlock( &p_dlg->lock );
341 lua_SetDialogUpdate( L, 1 );
346 /** Update the dialog immediately */
347 static int vlclua_dialog_update( lua_State *L )
349 vlc_object_t *p_mgr = vlclua_get_this( L );
351 extension_dialog_t **pp_dlg =
352 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
353 if( !pp_dlg || !*pp_dlg )
354 return luaL_error( L, "Can't get pointer to dialog" );
355 extension_dialog_t *p_dlg = *pp_dlg;
357 // Updating dialog immediately
358 dialog_ExtensionUpdate( p_mgr, p_dlg );
361 lua_SetDialogUpdate( L, 0 );
366 static void lua_SetDialogUpdate( lua_State *L, int flag )
368 /* Set entry in the Lua registry */
369 lua_pushlightuserdata( L, (void*) &key_update );
370 lua_pushinteger( L, flag );
371 lua_settable( L, LUA_REGISTRYINDEX );
374 static int lua_GetDialogUpdate( lua_State *L )
376 /* Read entry in the Lua registry */
377 lua_pushlightuserdata( L, (void*) &key_update );
378 lua_gettable( L, LUA_REGISTRYINDEX );
379 return luaL_checkinteger( L, -1 );
382 /** Manually update a dialog
383 * This can be called after a lua_pcall
384 * @return SUCCESS if there is no dialog or the update was successful
385 * @todo If there can be multiple dialogs, this function will have to
386 * be fixed (lookup for dialog)
388 int lua_DialogFlush( lua_State *L )
390 lua_getglobal( L, "vlc" );
391 lua_getfield( L, -1, "__dialog" );
392 extension_dialog_t *p_dlg = ( extension_dialog_t* )lua_topointer( L, -1 );
397 int i_ret = VLC_SUCCESS;
398 if( lua_GetDialogUpdate( L ) )
400 i_ret = dialog_ExtensionUpdate( vlclua_get_this( L ), p_dlg );
401 lua_SetDialogUpdate( L, 0 );
408 * Create a button: add_button
409 * Arguments: text, function (as string)
412 static int vlclua_dialog_add_button( lua_State *L )
414 /* Verify arguments */
415 if( !lua_isstring( L, 2 ) || !lua_isfunction( L, 3 ) )
416 return luaL_error( L, "dialog:add_button usage: (text, func)" );
418 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
419 p_widget->type = EXTENSION_WIDGET_BUTTON;
420 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
422 lua_pushlightuserdata( L, p_widget );
423 lua_pushvalue( L, 3 );
424 lua_settable( L, LUA_REGISTRYINDEX );
425 p_widget->p_sys = NULL;
427 return vlclua_create_widget_inner( L, 2, p_widget );
431 * Create a text label: add_label
435 static int vlclua_dialog_add_label( lua_State *L )
437 /* Verify arguments */
438 if( !lua_isstring( L, 2 ) )
439 return luaL_error( L, "dialog:add_label usage: (text)" );
440 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
441 p_widget->type = EXTENSION_WIDGET_LABEL;
442 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
444 return vlclua_create_widget_inner( L, 1, p_widget );
448 * Create a text area: add_html, add_text_input, add_password
449 * Arguments: text (may be nil)
450 * Qt: QLineEdit (Text/Password) or QTextArea (HTML)
452 static int vlclua_dialog_add_text_inner( lua_State *L, int i_type )
454 /* Verify arguments */
455 if( !lua_isstring( L, 2 ) && !lua_isnil( L, 2 ) )
456 return luaL_error( L, "dialog:add_text_input usage: (text = nil)" );
458 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
459 p_widget->type = i_type;
460 if( !lua_isnil( L, 2 ) )
461 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
463 return vlclua_create_widget_inner( L, 1, p_widget );
467 * Create a checkable box: add_check_box
468 * Arguments: text, checked (as bool)
471 static int vlclua_dialog_add_check_box( lua_State *L )
473 /* Verify arguments */
474 if( !lua_isstring( L, 2 ) )
475 return luaL_error( L, "dialog:add_check_box usage: (text, checked)" );
477 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
478 p_widget->type = EXTENSION_WIDGET_CHECK_BOX;
479 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
480 p_widget->b_checked = lua_toboolean( L, 3 );
482 return vlclua_create_widget_inner( L, 2, p_widget );
486 * Create a drop-down list (non editable)
489 * @todo make it editable?
491 static int vlclua_dialog_add_dropdown( lua_State *L )
493 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
494 p_widget->type = EXTENSION_WIDGET_DROPDOWN;
496 return vlclua_create_widget_inner( L, 0, p_widget );
500 * Create a list panel (multiple selection)
504 static int vlclua_dialog_add_list( lua_State *L )
506 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
507 p_widget->type = EXTENSION_WIDGET_LIST;
509 return vlclua_create_widget_inner( L, 0, p_widget );
513 * Create an image label
515 * Qt: QLabel with setPixmap( QPixmap& )
517 static int vlclua_dialog_add_image( lua_State *L )
519 /* Verify arguments */
520 if( !lua_isstring( L, 2 ) )
521 return luaL_error( L, "dialog:add_image usage: (filename)" );
523 extension_widget_t *p_widget = calloc( 1, sizeof( extension_widget_t ) );
524 p_widget->type = EXTENSION_WIDGET_IMAGE;
525 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
527 return vlclua_create_widget_inner( L, 1, p_widget );
531 * Internal helper to finalize the creation of a widget
533 * @param i_args Number of arguments before "row" (0 or more)
534 * @param p_widget The widget to add
536 static int vlclua_create_widget_inner( lua_State *L, int i_args,
537 extension_widget_t *p_widget )
539 int arg = i_args + 2;
542 extension_dialog_t **pp_dlg =
543 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
544 if( !pp_dlg || !*pp_dlg )
545 return luaL_error( L, "Can't get pointer to dialog" );
546 extension_dialog_t *p_dlg = *pp_dlg;
548 /* Set parent dialog */
549 p_widget->p_dialog = p_dlg;
551 /* Set common arguments: col, row, hspan, vspan, width, height */
552 if( lua_isnumber( L, arg ) )
553 p_widget->i_column = luaL_checkinteger( L, arg );
554 else goto end_of_args;
555 if( lua_isnumber( L, ++arg ) )
556 p_widget->i_row = luaL_checkinteger( L, arg );
557 else goto end_of_args;
558 if( lua_isnumber( L, ++arg ) )
559 p_widget->i_horiz_span = luaL_checkinteger( L, arg );
560 else goto end_of_args;
561 if( lua_isnumber( L, ++arg ) )
562 p_widget->i_vert_span = luaL_checkinteger( L, arg );
563 else goto end_of_args;
564 if( lua_isnumber( L, ++arg ) )
565 p_widget->i_width = luaL_checkinteger( L, arg );
566 else goto end_of_args;
567 if( lua_isnumber( L, ++arg ) )
568 p_widget->i_height = luaL_checkinteger( L, arg );
569 else goto end_of_args;
572 vlc_mutex_lock( &p_dlg->lock );
574 /* Add the widget to the dialog descriptor */
575 AddWidget( p_dlg, p_widget );
577 vlc_mutex_unlock( &p_dlg->lock );
579 /* Create meta table */
580 extension_widget_t **pp_widget = lua_newuserdata( L, sizeof( extension_widget_t* ) );
581 *pp_widget = p_widget;
582 if( luaL_newmetatable( L, "widget" ) )
585 luaL_register( L, NULL, vlclua_widget_reg );
586 lua_setfield( L, -2, "__index" );
588 lua_setmetatable( L, -2 );
590 lua_SetDialogUpdate( L, 1 );
595 static int vlclua_widget_set_text( lua_State *L )
598 extension_widget_t **pp_widget =
599 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
600 if( !pp_widget || !*pp_widget )
601 return luaL_error( L, "Can't get pointer to widget" );
602 extension_widget_t *p_widget = *pp_widget;
604 /* Verify arguments */
605 if( !lua_isstring( L, 2 ) )
606 return luaL_error( L, "widget:set_text usage: (text)" );
608 /* Verify widget type */
609 switch( p_widget->type )
611 case EXTENSION_WIDGET_LABEL:
612 case EXTENSION_WIDGET_BUTTON:
613 case EXTENSION_WIDGET_HTML:
614 case EXTENSION_WIDGET_TEXT_FIELD:
615 case EXTENSION_WIDGET_PASSWORD:
616 case EXTENSION_WIDGET_DROPDOWN:
617 case EXTENSION_WIDGET_CHECK_BOX:
619 case EXTENSION_WIDGET_LIST:
620 case EXTENSION_WIDGET_IMAGE:
622 return luaL_error( L, "method set_text not valid for this widget" );
625 vlc_mutex_lock( &p_widget->p_dialog->lock );
628 p_widget->b_update = true;
629 free( p_widget->psz_text );
630 p_widget->psz_text = strdup( luaL_checkstring( L, 2 ) );
632 vlc_mutex_unlock( &p_widget->p_dialog->lock );
634 lua_SetDialogUpdate( L, 1 );
639 static int vlclua_widget_get_text( 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 /* Verify widget type */
649 switch( p_widget->type )
651 case EXTENSION_WIDGET_LABEL:
652 case EXTENSION_WIDGET_BUTTON:
653 case EXTENSION_WIDGET_HTML:
654 case EXTENSION_WIDGET_TEXT_FIELD:
655 case EXTENSION_WIDGET_PASSWORD:
656 case EXTENSION_WIDGET_DROPDOWN:
657 case EXTENSION_WIDGET_CHECK_BOX:
659 case EXTENSION_WIDGET_LIST:
660 case EXTENSION_WIDGET_IMAGE:
662 return luaL_error( L, "method get_text not valid for this widget" );
665 extension_dialog_t *p_dlg = p_widget->p_dialog;
666 vlc_mutex_lock( &p_dlg->lock );
668 char *psz_text = NULL;
669 if( p_widget->psz_text )
670 psz_text = strdup( p_widget->psz_text );
671 vlc_mutex_unlock( &p_dlg->lock );
673 lua_pushstring( L, psz_text );
679 static int vlclua_widget_get_checked( lua_State *L )
682 extension_widget_t **pp_widget =
683 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
684 if( !pp_widget || !*pp_widget )
685 return luaL_error( L, "Can't get pointer to widget" );
686 extension_widget_t *p_widget = *pp_widget;
688 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
689 return luaL_error( L, "method get_checked not valid for this widget" );
691 vlc_mutex_lock( &p_widget->p_dialog->lock );
692 lua_pushboolean( L, p_widget->b_checked );
693 vlc_mutex_unlock( &p_widget->p_dialog->lock );
698 static int vlclua_widget_add_value( lua_State *L )
701 extension_widget_t **pp_widget =
702 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
703 if( !pp_widget || !*pp_widget )
704 return luaL_error( L, "Can't get pointer to widget" );
705 extension_widget_t *p_widget = *pp_widget;
707 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
708 && p_widget->type != EXTENSION_WIDGET_LIST )
709 return luaL_error( L, "method add_value not valid for this widget" );
711 if( !lua_isstring( L, 2 ) )
712 return luaL_error( L, "widget:add_value usage: (text, id = 0)" );
714 struct extension_widget_value_t *p_value,
715 *p_new_value = calloc( 1, sizeof( struct extension_widget_value_t ) );
716 p_new_value->psz_text = strdup( luaL_checkstring( L, 2 ) );
717 p_new_value->i_id = lua_tointeger( L, 3 );
719 vlc_mutex_lock( &p_widget->p_dialog->lock );
721 if( !p_widget->p_values )
723 p_widget->p_values = p_new_value;
724 if( p_widget->type == EXTENSION_WIDGET_DROPDOWN )
725 p_new_value->b_selected = true;
729 for( p_value = p_widget->p_values;
730 p_value->p_next != NULL;
731 p_value = p_value->p_next )
732 { /* Do nothing, iterate to find the end */ }
733 p_value->p_next = p_new_value;
736 p_widget->b_update = true;
737 vlc_mutex_unlock( &p_widget->p_dialog->lock );
739 lua_SetDialogUpdate( L, 1 );
744 static int vlclua_widget_get_value( lua_State *L )
747 extension_widget_t **pp_widget =
748 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
749 if( !pp_widget || !*pp_widget )
750 return luaL_error( L, "Can't get pointer to widget" );
751 extension_widget_t *p_widget = *pp_widget;
753 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN )
754 return luaL_error( L, "method get_value not valid for this widget" );
756 vlc_mutex_lock( &p_widget->p_dialog->lock );
758 struct extension_widget_value_t *p_value;
759 for( p_value = p_widget->p_values;
761 p_value = p_value->p_next )
763 if( p_value->b_selected )
765 lua_pushinteger( L, p_value->i_id );
766 lua_pushstring( L, p_value->psz_text );
767 vlc_mutex_unlock( &p_widget->p_dialog->lock );
772 vlc_mutex_unlock( &p_widget->p_dialog->lock );
774 lua_pushinteger( L, -1 );
779 static int vlclua_widget_clear( lua_State *L )
782 extension_widget_t **pp_widget =
783 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
784 if( !pp_widget || !*pp_widget )
785 return luaL_error( L, "Can't get pointer to widget" );
786 extension_widget_t *p_widget = *pp_widget;
788 if( p_widget->type != EXTENSION_WIDGET_DROPDOWN
789 && p_widget->type != EXTENSION_WIDGET_LIST )
790 return luaL_error( L, "method clear not valid for this widget" );
792 struct extension_widget_value_t *p_value, *p_next;
794 vlc_mutex_lock( &p_widget->p_dialog->lock );
796 for( p_value = p_widget->p_values;
800 p_next = p_value->p_next;
801 free( p_value->psz_text );
805 p_widget->p_values = NULL;
806 p_widget->b_update = true;
808 vlc_mutex_unlock( &p_widget->p_dialog->lock );
810 lua_SetDialogUpdate( L, 1 );
815 static int vlclua_widget_get_selection( lua_State *L )
818 extension_widget_t **pp_widget =
819 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
820 if( !pp_widget || !*pp_widget )
821 return luaL_error( L, "Can't get pointer to widget" );
822 extension_widget_t *p_widget = *pp_widget;
824 if( p_widget->type != EXTENSION_WIDGET_LIST )
825 return luaL_error( L, "method get_selection not valid for this widget" );
827 /* Create empty table */
830 vlc_mutex_lock( &p_widget->p_dialog->lock );
832 struct extension_widget_value_t *p_value;
833 for( p_value = p_widget->p_values;
835 p_value = p_value->p_next )
837 if( p_value->b_selected )
839 lua_pushinteger( L, p_value->i_id );
840 lua_pushstring( L, p_value->psz_text );
841 lua_settable( L, -3 );
845 vlc_mutex_unlock( &p_widget->p_dialog->lock );
851 static int vlclua_widget_set_checked( lua_State *L )
854 extension_widget_t **pp_widget =
855 (extension_widget_t **) luaL_checkudata( L, 1, "widget" );
856 if( !pp_widget || !*pp_widget )
857 return luaL_error( L, "Can't get pointer to widget" );
858 extension_widget_t *p_widget = *pp_widget;
860 if( p_widget->type != EXTENSION_WIDGET_CHECK_BOX )
861 return luaL_error( L, "method set_checked not valid for this widget" );
863 /* Verify arguments */
864 if( !lua_isboolean( L, 2 ) )
865 return luaL_error( L, "widget:set_checked usage: (bool)" );
867 vlc_mutex_lock( &p_widget->p_dialog->lock );
869 bool b_old_check = p_widget->b_checked;
870 p_widget->b_checked = lua_toboolean( L, 2 );
872 vlc_mutex_unlock( &p_widget->p_dialog->lock );
874 if( b_old_check != p_widget->b_checked )
876 /* Signal interface of the change */
877 p_widget->b_update = true;
878 lua_SetDialogUpdate( L, 1 );
885 * Delete a widget from a dialog
886 * Remove it from the list once it has been safely destroyed by the interface
887 * @note This will always update the dialog
889 static int vlclua_dialog_delete_widget( lua_State *L )
892 extension_dialog_t **pp_dlg =
893 (extension_dialog_t**) luaL_checkudata( L, 1, "dialog" );
894 if( !pp_dlg || !*pp_dlg )
895 return luaL_error( L, "Can't get pointer to dialog" );
896 extension_dialog_t *p_dlg = *pp_dlg;
899 if( !lua_isuserdata( L, 2 ) )
900 return luaL_error( L, "Argument to del_widget is not a widget" );
903 extension_widget_t **pp_widget =
904 (extension_widget_t **) luaL_checkudata( L, 2, "widget" );
905 if( !pp_widget || !*pp_widget )
906 return luaL_error( L, "Can't get pointer to widget" );
907 extension_widget_t *p_widget = *pp_widget;
911 if( p_widget->type == EXTENSION_WIDGET_BUTTON )
913 /* Remove button action from registry */
914 lua_pushlightuserdata( L, p_widget );
916 lua_settable( L, LUA_REGISTRYINDEX );
919 vlc_object_t *p_mgr = vlclua_get_this( L );
921 p_widget->b_kill = true;
923 lua_SetDialogUpdate( L, 0 ); // Reset update flag
924 int i_ret = dialog_ExtensionUpdate( p_mgr, p_dlg );
926 if( i_ret != VLC_SUCCESS )
928 return luaL_error( L, "Could not delete widget" );
931 vlc_mutex_lock( &p_dlg->lock );
933 /* Same remarks as for dialog delete.
934 * If the dialog is deleted or about to be deleted, then there is no
935 * need to wait on this particular widget that already doesn't exist
936 * anymore in the UI */
937 while( p_widget->p_sys_intf != NULL && !p_dlg->b_kill
938 && p_dlg->p_sys_intf != NULL )
940 vlc_cond_wait( &p_dlg->cond, &p_dlg->lock );
943 i_ret = DeleteWidget( p_dlg, p_widget );
945 vlc_mutex_unlock( &p_dlg->lock );
947 if( i_ret != VLC_SUCCESS )
949 return luaL_error( L, "Could not remove widget from list" );
957 * Below this line, no Lua specific code.
963 * Add a widget to the widget list of a dialog
964 * @note Must be entered with lock on dialog
966 static void AddWidget( extension_dialog_t *p_dialog,
967 extension_widget_t *p_widget )
969 ARRAY_APPEND( p_dialog->widgets, p_widget );
973 * Remove a widget from the widget list of a dialog
974 * @note The widget MUST have been safely killed before
975 * @note Must be entered with lock on dialog
977 static int DeleteWidget( extension_dialog_t *p_dialog,
978 extension_widget_t *p_widget )
982 extension_widget_t *p_iter;
983 FOREACH_ARRAY( p_iter, p_dialog->widgets )
986 if( p_iter == p_widget )
997 ARRAY_REMOVE( p_dialog->widgets, pos );
999 /* Now free the data */
1000 free( p_widget->p_sys );
1001 struct extension_widget_value_t *p_value = p_widget->p_values;
1004 free( p_value->psz_text );
1005 struct extension_widget_value_t *old = p_value;
1006 p_value = p_value->p_next;
1009 free( p_widget->psz_text );