]> git.sesse.net Git - vlc/blob - modules/gui/hildon/maemo_menus.c
macosx: disable extensions submenu when they are no items to display
[vlc] / modules / gui / hildon / maemo_menus.c
1 /*****************************************************************************
2  * maemo_menus.c : menus creation for the maemo plugin
3  *****************************************************************************
4  * Copyright (C) 2010 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #include <vlc_common.h>
25 #include <vlc_interface.h>
26
27 #include <gtk/gtk.h>
28
29 #include "maemo.h"
30 #include "maemo_callbacks.h"
31
32 /*****************************************************************************
33  * Local prototypes
34  *****************************************************************************/
35 static GtkMenu *Populate( intf_thread_t *p_intf, GtkMenu *menu,
36                           const char **varnames, vlc_object_t **objects,
37                           unsigned int elements );
38
39 /*****************************************************************************
40  * Utility functions
41  *****************************************************************************/
42 static input_thread_t *get_input(intf_thread_t *p_intf)
43 {
44     return p_intf->p_sys->p_input;
45 }
46
47 static vlc_object_t *get_vout(intf_thread_t *p_intf)
48 {
49     return (vlc_object_t *)(p_intf->p_sys->p_input ?
50                             input_GetVout( p_intf->p_sys->p_input ) : 0);
51 }
52
53 static vlc_object_t *get_aout(intf_thread_t *p_intf)
54 {
55     return (vlc_object_t *)(p_intf->p_sys->p_input ?
56                             input_GetAout( p_intf->p_sys->p_input ) : 0);
57 }
58
59 static gint quit_event( GtkWidget *widget, gpointer data )
60 {
61     intf_thread_t *p_intf = (intf_thread_t *)data;
62     (void)widget;
63     libvlc_Quit( p_intf->p_libvlc );
64     return TRUE;
65 }
66
67 /*****************************************************************************
68  * Definitions of variables for the dynamic menus
69  *****************************************************************************/
70 #define SIZE_LIST 20
71
72 #define PUSH_VAR( var ) \
73     ppsz_varnames[index] = var; \
74     p_objects[index] = VLC_OBJECT(p_object); \
75     if(index < SIZE_LIST - 1) index++; \
76     ppsz_varnames[index] = 0; p_objects[index] = 0;
77
78 #define PUSH_INPUTVAR( var ) \
79     ppsz_varnames[index] = var; \
80     p_objects[index] = VLC_OBJECT(p_input); \
81     if(index < SIZE_LIST - 1) index++; \
82     ppsz_varnames[index] = 0; p_objects[index] = 0;
83
84 #define ADD_MENU_ITEM( label, callback ) \
85     item = gtk_menu_item_new_with_label( label ); \
86     gtk_menu_append( main_menu, item ); \
87     g_signal_connect( GTK_OBJECT( item ), "activate", G_CALLBACK( callback ), \
88                       p_intf );
89
90 #define ADD_SEPARATOR() \
91     item = gtk_separator_menu_item_new(); \
92     gtk_menu_append( main_menu, item );
93
94
95
96 static GtkMenu *create_video_menu( intf_thread_t *p_intf )
97 {
98     vlc_object_t *p_object = get_vout(p_intf);
99     input_thread_t *p_input = get_input(p_intf);;
100
101     vlc_object_t *p_objects[SIZE_LIST];
102     const char *ppsz_varnames[SIZE_LIST];
103     int index = 0;
104
105     PUSH_INPUTVAR( "video-es" );
106     PUSH_INPUTVAR( "spu-es" );
107     PUSH_VAR( "fullscreen" );
108     PUSH_VAR( "video-wallpaper" );
109     PUSH_VAR( "video-snapshot" );
110     PUSH_VAR( "zoom" );
111     PUSH_VAR( "autoscale" );
112     PUSH_VAR( "aspect-ratio" );
113     PUSH_VAR( "crop" );
114     PUSH_VAR( "deinterlace" );
115     PUSH_VAR( "deinterlace-mode" );
116     PUSH_VAR( "postprocess" );
117
118     GtkWidget *menu = gtk_menu_new();
119     return Populate( p_intf, GTK_MENU(menu), ppsz_varnames, p_objects, index );
120 }
121
122 static GtkMenu *create_audio_menu( intf_thread_t *p_intf )
123 {
124     vlc_object_t *p_object = get_aout(p_intf);
125     input_thread_t *p_input = get_input(p_intf);;
126
127     vlc_object_t *p_objects[SIZE_LIST];
128     const char *ppsz_varnames[SIZE_LIST];
129     int index = 0;
130
131     PUSH_INPUTVAR( "audio-es" );
132     PUSH_VAR( "audio-channels" );
133     PUSH_VAR( "audio-device" );
134     PUSH_VAR( "visual" );
135
136     GtkWidget *menu = gtk_menu_new();
137     return Populate( p_intf, GTK_MENU(menu), ppsz_varnames, p_objects, index );
138 }
139
140 static GtkMenu *create_input_menu( intf_thread_t *p_intf )
141 {
142     input_thread_t *p_object = get_input(p_intf);
143
144     vlc_object_t *p_objects[SIZE_LIST];
145     const char *ppsz_varnames[SIZE_LIST];
146     int index = 0;
147
148     PUSH_VAR( "bookmark" );
149     PUSH_VAR( "title" );
150     PUSH_VAR( "chapter" );
151     PUSH_VAR( "navigation" );
152     PUSH_VAR( "program" );
153
154     GtkWidget *menu = gtk_menu_new();
155     return Populate( p_intf, GTK_MENU(menu), ppsz_varnames, p_objects, index );
156 }
157
158 static void toplevel_menu_callback(GtkMenuItem *menuitem, gpointer data)
159 {
160     intf_thread_t *p_intf = (intf_thread_t *)data;
161     GtkMenu *(*pf_menu)(intf_thread_t *) = 0;
162     GtkMenu *menu;
163
164     if(menuitem == p_intf->p_sys->menu_input) pf_menu = create_input_menu;
165     else if(menuitem == p_intf->p_sys->menu_audio) pf_menu = create_audio_menu;
166     else if(menuitem == p_intf->p_sys->menu_video) pf_menu = create_video_menu;
167     else return;
168
169     menu = GTK_MENU(gtk_menu_item_get_submenu(menuitem));
170     if(menu) gtk_object_destroy( GTK_OBJECT(menu) );
171     menu = pf_menu(p_intf);
172     gtk_menu_item_set_submenu(menuitem, GTK_WIDGET(menu));
173     gtk_widget_show_all( GTK_WIDGET(menuitem) );
174 }
175
176 GtkWidget *create_menu( intf_thread_t *p_intf )
177 {
178     intf_sys_t *p_sys = p_intf->p_sys;
179     GtkWidget *main_menu, *item;
180
181     /* Creating the main menu */
182     main_menu = gtk_menu_new();
183
184     /* Filling the menu */
185     ADD_MENU_ITEM( "Open", open_cb );
186     ADD_MENU_ITEM( "Open Address", open_address_cb );
187     ADD_MENU_ITEM( "Open Webcam", open_webcam_cb );
188     ADD_SEPARATOR();
189
190     item = gtk_menu_item_new_with_label ("Playback");
191     p_sys->menu_input = GTK_MENU_ITEM(item);
192     gtk_menu_bar_append(main_menu, item);
193     g_signal_connect( GTK_OBJECT(item), "activate",
194                       G_CALLBACK( toplevel_menu_callback ), p_intf );
195
196     item = gtk_menu_item_new_with_label ("Audio");
197     p_sys->menu_audio = GTK_MENU_ITEM(item);
198     gtk_menu_bar_append(main_menu, item);
199     g_signal_connect( GTK_OBJECT(item), "activate",
200                       G_CALLBACK( toplevel_menu_callback ), p_intf );
201
202     item = gtk_menu_item_new_with_label ("Video");
203     p_sys->menu_video = GTK_MENU_ITEM(item);
204     gtk_menu_bar_append(main_menu, item);
205     g_signal_connect( GTK_OBJECT(item), "activate",
206                       G_CALLBACK( toplevel_menu_callback ), p_intf );
207
208     toplevel_menu_callback(p_sys->menu_input, p_intf);
209     toplevel_menu_callback(p_sys->menu_video, p_intf);
210     toplevel_menu_callback(p_sys->menu_audio, p_intf);
211
212     ADD_SEPARATOR();
213     ADD_MENU_ITEM( "Exit", quit_event );
214
215     gtk_widget_show_all( main_menu );
216     return main_menu;
217 }
218
219 /*************************************************************************
220  * Builders for automenus
221  *************************************************************************/
222 enum
223 {
224     ITEM_NORMAL,
225     ITEM_CHECK,
226     ITEM_RADIO
227 };
228
229 typedef struct VlcMenuItemClass
230 {
231   GtkRadioMenuItemClass menuitemclass;
232
233 } VlcMenuItemClass;
234
235 typedef struct VlcMenuItem
236 {
237   GtkRadioMenuItem menuitem;
238
239   vlc_object_t *p_obj;
240   int i_type;
241   vlc_value_t val;
242   const char *psz_var;
243
244 } VlcMenuItem;
245
246 static void vlc_menu_item_destroy (GtkObject *object)
247 {
248   VlcMenuItem *menuitem = (VlcMenuItem *)object;
249
250   if(menuitem->i_type == VLC_VAR_STRING && menuitem->val.psz_string)
251       free(menuitem->val.psz_string);
252   gtk_object_destroy( object );
253 }
254
255 static void vlc_menu_item_class_init (VlcMenuItemClass *klass)
256 {
257     GtkObjectClass *object_class = (GtkObjectClass*)klass;
258     object_class->destroy = vlc_menu_item_destroy;
259 }
260
261 static void vlc_menu_item_init (VlcMenuItem *menuitem){(void)menuitem;}
262
263 static GtkType vlc_menu_item_get_type (void)
264 {
265     static GtkType vlc_menu_item_type = 0;
266
267     if (!vlc_menu_item_type)
268     {
269         static const GtkTypeInfo vlc_menu_item_info =
270         {
271             (char *)"VlcMenuItem",
272             sizeof (VlcMenuItem),
273             sizeof (VlcMenuItemClass),
274             (GtkClassInitFunc) vlc_menu_item_class_init,
275             (GtkObjectInitFunc) vlc_menu_item_init,
276             /* reserved_1 */ NULL,
277             /* reserved_2 */ NULL,
278             (GtkClassInitFunc) NULL,
279         };
280
281         vlc_menu_item_type = gtk_type_unique (GTK_TYPE_MENU_ITEM, &vlc_menu_item_info);
282     }
283
284     return vlc_menu_item_type;
285 }
286
287 static GtkType vlc_check_menu_item_get_type (void)
288 {
289     static GtkType vlc_check_menu_item_type = 0;
290
291     if (!vlc_check_menu_item_type)
292     {
293         static const GtkTypeInfo vlc_check_menu_item_info =
294         {
295             (char *)"VlcCheckMenuItem",
296             sizeof (VlcMenuItem),
297             sizeof (VlcMenuItemClass),
298             (GtkClassInitFunc) vlc_menu_item_class_init,
299             (GtkObjectInitFunc) vlc_menu_item_init,
300             /* reserved_1 */ NULL,
301             /* reserved_2 */ NULL,
302             (GtkClassInitFunc) NULL,
303         };
304
305         vlc_check_menu_item_type = gtk_type_unique (GTK_TYPE_CHECK_MENU_ITEM, &vlc_check_menu_item_info);
306     }
307
308     return vlc_check_menu_item_type;
309 }
310
311 static GtkType vlc_radio_menu_item_get_type (void)
312 {
313     static GtkType vlc_radio_menu_item_type = 0;
314
315     if (!vlc_radio_menu_item_type)
316     {
317         static const GtkTypeInfo vlc_radio_menu_item_info =
318         {
319             (char *)"VlcRadioMenuItem",
320             sizeof (VlcMenuItem),
321             sizeof (VlcMenuItemClass),
322             (GtkClassInitFunc) vlc_menu_item_class_init,
323             (GtkObjectInitFunc) vlc_menu_item_init,
324             /* reserved_1 */ NULL,
325             /* reserved_2 */ NULL,
326             (GtkClassInitFunc) NULL,
327         };
328
329         vlc_radio_menu_item_type = gtk_type_unique (GTK_TYPE_RADIO_MENU_ITEM, &vlc_radio_menu_item_info);
330     }
331
332     return vlc_radio_menu_item_type;
333 }
334
335 static GtkWidget *vlc_menu_item_new (vlc_object_t *p_obj, int i_type,
336                                      vlc_value_t val, const char *var)
337 {
338     VlcMenuItem *item;
339
340     switch(i_type)
341     {
342     case ITEM_CHECK:
343       item = (VlcMenuItem *)gtk_type_new (vlc_check_menu_item_get_type ());
344       break;
345     case ITEM_RADIO:
346       item = (VlcMenuItem *)gtk_type_new (vlc_radio_menu_item_get_type ());
347       break;
348     default:
349       item = (VlcMenuItem *)gtk_type_new (vlc_menu_item_get_type ());
350       break;
351     }
352     item->p_obj = p_obj;
353     item->i_type = i_type;
354     item->val = val;
355     item->psz_var = var;
356     return GTK_WIDGET (item);
357 }
358
359 /****/
360
361 static int CreateChoicesMenu( intf_thread_t *p_intf, GtkMenu *submenu, const char *psz_var,
362                               vlc_object_t *p_object, bool b_root );
363
364 static void menu_callback(GtkMenuItem *menuitem, gpointer user_data)
365 {
366     VlcMenuItem *item = (VlcMenuItem *)menuitem;
367     vlc_object_t *p_object = item->p_obj;
368     (void)user_data;
369     if( p_object == NULL ) return;
370     var_Set( p_object, item->psz_var, item->val );
371 }
372
373 static void CreateAndConnect( intf_thread_t *p_intf,
374         GtkMenu *menu, const char *psz_var,
375         const char *text, const char *help,
376         int i_item_type, vlc_object_t *p_obj,
377         vlc_value_t val, int i_val_type,
378         bool checked )
379 {
380     GtkMenuItem *menu_item =
381         (GtkMenuItem *)vlc_menu_item_new (p_obj, i_item_type, val, psz_var );
382
383     (void)help; (void)i_val_type;
384
385 #if GTK_CHECK_VERSION(2,16,0)
386     gtk_menu_item_set_label (menu_item, text ? text : psz_var);
387 #else
388     GtkWidget *accel_label = gtk_accel_label_new(text ? text : psz_var);
389     gtk_misc_set_alignment(GTK_MISC (accel_label), 0.0, 0.5);
390     gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
391     gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), GTK_WIDGET(menu_item));
392     gtk_widget_show (accel_label);
393 #endif /* GTK_CHECK_VERSION(2,16,0) */
394
395     gtk_menu_append( GTK_WIDGET(menu), GTK_WIDGET(menu_item) );
396
397     if( i_item_type == ITEM_CHECK || i_item_type == ITEM_RADIO )
398         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), checked);
399
400     g_signal_connect( GTK_OBJECT(menu_item), "activate", G_CALLBACK( menu_callback ),
401                       p_intf );
402 }
403
404 static bool IsMenuEmpty( const char *psz_var,
405                          vlc_object_t *p_object,
406                          bool b_root )
407 {
408     vlc_value_t val, val_list;
409     int i_type, i_result, i;
410
411     /* Check the type of the object variable */
412     i_type = var_Type( p_object, psz_var );
413
414     /* Check if we want to display the variable */
415     if( !( i_type & VLC_VAR_HASCHOICE ) ) return false;
416
417     var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
418     if( val.i_int == 0 ) return true;
419
420     if( ( i_type & VLC_VAR_TYPE ) != VLC_VAR_VARIABLE )
421     {
422         if( val.i_int == 1 && b_root ) return true;
423         else return false;
424     }
425
426     /* Check children variables in case of VLC_VAR_VARIABLE */
427     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
428     {
429         return true;
430     }
431
432     for( i = 0, i_result = true; i < val_list.p_list->i_count; i++ )
433     {
434         if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
435                     p_object, false ) )
436         {
437             i_result = false;
438             break;
439         }
440     }
441
442     /* clean up everything */
443     var_FreeList( &val_list, NULL );
444
445     return i_result;
446 }
447
448 static void UpdateItem( intf_thread_t *p_intf, GtkMenu *menu,
449                  const char *psz_var, vlc_object_t *p_object, bool b_submenu )
450 {
451     vlc_value_t val, text;
452     int i_type;
453
454     /* Check the type of the object variable */
455     /* This HACK is needed so we have a radio button for audio and video tracks
456        instread of a checkbox */
457     if( !strcmp( psz_var, "audio-es" )
458      || !strcmp( psz_var, "video-es" ) )
459         i_type = VLC_VAR_INTEGER | VLC_VAR_HASCHOICE;
460     else
461         i_type = var_Type( p_object, psz_var );
462
463     switch( i_type & VLC_VAR_TYPE )
464     {
465         case VLC_VAR_VOID:
466         case VLC_VAR_BOOL:
467         case VLC_VAR_VARIABLE:
468         case VLC_VAR_STRING:
469         case VLC_VAR_INTEGER:
470         case VLC_VAR_FLOAT:
471             break;
472         default:
473             /* Variable doesn't exist or isn't handled */
474             return;
475     }
476
477     /* Make sure we want to display the variable */
478     if( !g_list_length(GTK_MENU_SHELL(menu)->children) && IsMenuEmpty( psz_var, p_object, true ) )
479     {
480         return;
481     }
482
483     /* Get the descriptive name of the variable */
484     int i_ret = var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );
485     if( i_ret != VLC_SUCCESS )
486     {
487         text.psz_string = NULL;
488     }
489
490     /* Some specific stuff */
491     bool forceDisabled = false;
492     if( !strcmp( psz_var, "spu-es" ) )
493     {
494         vlc_object_t *p_vout = get_vout(p_intf);
495         forceDisabled = ( p_vout == NULL );
496         if( p_vout ) vlc_object_release( p_vout );
497     }
498
499     if( i_type & VLC_VAR_HASCHOICE )
500     {
501         /* Append choices menu */
502         if( b_submenu )
503         {
504             GtkWidget *item =
505                 gtk_menu_item_new_with_label( text.psz_string ? text.psz_string : psz_var );
506             GtkWidget *submenu = gtk_menu_new( );
507             gtk_menu_append( menu, item );
508             gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
509             if( CreateChoicesMenu( p_intf, GTK_MENU(submenu), psz_var, p_object, true ) )
510                 gtk_widget_set_sensitive(item, false);
511
512             if( forceDisabled )
513                 gtk_widget_set_sensitive(item, false);
514         }
515         else
516         {
517
518             if( CreateChoicesMenu( p_intf, menu, psz_var, p_object, true ) )
519                 gtk_widget_set_sensitive(menu, false);
520         }
521         FREENULL( text.psz_string );
522         return;
523     }
524
525     switch( i_type & VLC_VAR_TYPE )
526     {
527         case VLC_VAR_VOID:
528             var_Get( p_object, psz_var, &val );
529             CreateAndConnect( p_intf, menu, psz_var, text.psz_string, "",
530                               ITEM_NORMAL, p_object, val, i_type, false );
531             break;
532
533         case VLC_VAR_BOOL:
534             var_Get( p_object, psz_var, &val );
535             val.b_bool = !val.b_bool;
536             CreateAndConnect( p_intf, menu, psz_var, text.psz_string, "",
537                               ITEM_CHECK, p_object, val, i_type, !val.b_bool );
538             break;
539     }
540     FREENULL( text.psz_string );
541 }
542
543 /** HACK for the navigation submenu:
544  * "title %2i" variables take the value 0 if not set
545  */
546 static bool CheckTitle( vlc_object_t *p_object, const char *psz_var )
547 {
548     int i_title = 0;
549     if( sscanf( psz_var, "title %2i", &i_title ) <= 0 )
550         return true;
551
552     int i_current_title = var_GetInteger( p_object, "title" );
553     return ( i_title == i_current_title );
554 }
555
556
557 static int CreateChoicesMenu( intf_thread_t *p_intf, GtkMenu *submenu, const char *psz_var,
558                        vlc_object_t *p_object, bool b_root )
559 {
560     vlc_value_t val, val_list, text_list;
561     int i_type, i;
562
563     /* Check the type of the object variable */
564     i_type = var_Type( p_object, psz_var );
565
566     /* Make sure we want to display the variable */
567     if( !g_list_length(GTK_MENU_SHELL(submenu)->children) &&
568         IsMenuEmpty( psz_var, p_object, b_root ) )
569         return VLC_EGENERIC;
570
571     switch( i_type & VLC_VAR_TYPE )
572     {
573         case VLC_VAR_VOID:
574         case VLC_VAR_BOOL:
575         case VLC_VAR_VARIABLE:
576         case VLC_VAR_STRING:
577         case VLC_VAR_INTEGER:
578         case VLC_VAR_FLOAT:
579             break;
580         default:
581             /* Variable doesn't exist or isn't handled */
582             return VLC_EGENERIC;
583     }
584
585     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
586                     &val_list, &text_list ) < 0 )
587     {
588         return VLC_EGENERIC;
589     }
590
591 #define CURVAL val_list.p_list->p_values[i]
592 #define CURTEXT text_list.p_list->p_values[i].psz_string
593
594     for( i = 0; i < val_list.p_list->i_count; i++ )
595     {
596         vlc_value_t another_val;
597         char string[16] = {0};
598         char *menutext = string;
599
600         switch( i_type & VLC_VAR_TYPE )
601         {
602             case VLC_VAR_VARIABLE:
603               {
604                 GtkWidget *subsubmenu = gtk_menu_new();
605                 GtkWidget *submenuitem =
606                     gtk_menu_item_new_with_label( CURTEXT ? CURTEXT : CURVAL.psz_string );
607                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), subsubmenu);
608                 gtk_menu_append( submenu, submenuitem );
609                 CreateChoicesMenu( p_intf, GTK_MENU(subsubmenu), CURVAL.psz_string, p_object, false );
610                 break;
611               }
612
613             case VLC_VAR_STRING:
614                 var_Get( p_object, psz_var, &val );
615                 another_val.psz_string = strdup( CURVAL.psz_string );
616                 menutext = CURTEXT ? CURTEXT : another_val.psz_string;
617                 CreateAndConnect( p_intf, submenu, psz_var, menutext, "",
618                                   ITEM_RADIO, p_object, another_val, i_type,
619                         val.psz_string && !strcmp( val.psz_string, CURVAL.psz_string ) );
620                 free( val.psz_string );
621                 break;
622
623             case VLC_VAR_INTEGER:
624                 var_Get( p_object, psz_var, &val );
625                 if( CURTEXT ) menutext = CURTEXT;
626                 else snprintf( menutext, sizeof(string)-1, "%"PRId64, CURVAL.i_int );
627                 CreateAndConnect( p_intf, submenu, psz_var, menutext, "",
628                                   ITEM_RADIO, p_object, CURVAL, i_type,
629                         ( CURVAL.i_int == val.i_int )
630                         && CheckTitle( p_object, psz_var ) );
631                 break;
632
633             case VLC_VAR_FLOAT:
634                 var_Get( p_object, psz_var, &val );
635                 if( CURTEXT ) menutext = CURTEXT;
636                 else snprintf( menutext, sizeof(string)-1, "%.2f", CURVAL.f_float );
637                 CreateAndConnect( p_intf, submenu, psz_var, menutext, "",
638                                   ITEM_RADIO, p_object, CURVAL, i_type,
639                                   CURVAL.f_float == val.f_float );
640                 break;
641
642             default:
643                 break;
644         }
645     }
646
647     /* clean up everything */
648     var_FreeList( &val_list, &text_list );
649
650 #undef CURVAL
651 #undef CURTEXT
652     return !g_list_length(GTK_MENU_SHELL(submenu)->children) ? VLC_EGENERIC : VLC_SUCCESS;
653 }
654
655 static GtkMenu *Populate( intf_thread_t *p_intf, GtkMenu *menu,
656                           const char **varnames, vlc_object_t **objects,
657                           unsigned int elements)
658 {
659     for( unsigned int i = 0; i < elements ; i++ )
660     {
661         if( (!varnames[i] || !*varnames[i]) &&
662             g_list_length(GTK_MENU_SHELL(menu)->children) )
663         {
664             gtk_menu_append( menu, gtk_separator_menu_item_new() );
665             continue;
666         }
667
668         if( objects[i] )
669         {
670             UpdateItem( p_intf, menu, varnames[i], objects[i], true );
671         }
672     }
673
674     if(!g_list_length(GTK_MENU_SHELL(menu)->children))
675     {
676         GtkWidget *menuitem = gtk_menu_item_new_with_label( "Empty" );
677         gtk_menu_append( menu, menuitem );
678         gtk_widget_set_sensitive(menuitem, false);
679     }
680
681     return menu;
682 }