]> git.sesse.net Git - vlc/blob - modules/gui/gtk/menu.c
479d1a2c93ef33116a9277af5727c30bef8d4b3a
[vlc] / modules / gui / gtk / menu.c
1 /*****************************************************************************
2  * menu.c : functions to handle menu items.
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: menu.c,v 1.8 2003/02/05 22:11:52 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Stéphane Borel <stef@via.ecp.fr>
9  *          Johan Bilien <jobi@via.ecp.fr>
10  *          Laurent Aimar <fenrir@via.ecp.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <sys/types.h>                                              /* off_t */
31 #include <stdlib.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/intf.h>
35 #include <vlc/aout.h>
36 #include <vlc/vout.h>
37
38 #ifdef MODULE_NAME_IS_gnome
39 #   include <gnome.h>
40 #else
41 #   include <gtk/gtk.h>
42 #endif
43
44 #include <string.h>
45
46 #include "gtk_callbacks.h"
47 #include "gtk_interface.h"
48 #include "gtk_support.h"
49
50 #include "playlist.h"
51 #include "common.h"
52
53 /*
54  * Local Prototypes
55  */
56 static gint GtkLanguageMenus( gpointer , GtkWidget *, es_descriptor_t *, gint,
57                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
58
59 void GtkMenubarAudioToggle   ( GtkCheckMenuItem *, gpointer );
60 void GtkPopupAudioToggle     ( GtkCheckMenuItem *, gpointer );
61 void GtkMenubarSubtitleToggle( GtkCheckMenuItem *, gpointer );
62 void GtkPopupSubtitleToggle  ( GtkCheckMenuItem *, gpointer );
63 static gint GtkTitleMenu( gpointer, GtkWidget *,
64                     void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
65 static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *,
66                           char *, int, int, int,
67                    void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) );
68
69 static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data );
70 static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data );
71 static gint GtkDeinterlaceMenus( gpointer          p_data,
72                                  GtkWidget *       p_root,
73                                  void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
74
75 gint GtkSetupMenus( intf_thread_t * p_intf );
76
77 /****************************************************************************
78  * Gtk*Toggle: callbacks to toggle the value of a checkmenuitem
79  ****************************************************************************
80  * We need separate functions for menubar and popup here since we can't use
81  * user_data to transmit intf_* and we need to refresh the other menu.
82  ****************************************************************************/
83
84 #define GTKLANGTOGGLE( window, menu, type, callback, b_update )         \
85     intf_thread_t *         p_intf;                                     \
86     GtkWidget *             p_menu;                                     \
87     es_descriptor_t *       p_es;                                       \
88                                                                         \
89     p_intf = GtkGetIntf( menuitem );                                    \
90                                                                         \
91     if( !p_intf->p_sys->b_update )                                      \
92     {                                                                   \
93         p_menu = GTK_WIDGET( gtk_object_get_data(                       \
94                    GTK_OBJECT( p_intf->p_sys->window ), (menu) ) );     \
95         p_es = (es_descriptor_t*)user_data;                             \
96                                                                         \
97         input_ToggleES( p_intf->p_sys->p_input,                         \
98                         p_es, menuitem->active );                       \
99                                                                         \
100         p_intf->p_sys->b_update = menuitem->active;                     \
101                                                                         \
102         if( p_intf->p_sys->b_update )                                   \
103         {                                                               \
104             GtkLanguageMenus( p_intf, p_menu, p_es, type, callback );   \
105         }                                                               \
106                                                                         \
107         p_intf->p_sys->b_update = VLC_FALSE;                            \
108     }
109
110 /*
111  * Audio
112  */
113
114 void GtkMenubarAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
115 {
116     GTKLANGTOGGLE( p_popup, "popup_language", AUDIO_ES,
117                    GtkPopupAudioToggle, b_audio_update );
118 }
119
120 void GtkPopupAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
121 {
122     GTKLANGTOGGLE( p_window, "menubar_audio", AUDIO_ES,
123                    GtkMenubarAudioToggle, b_audio_update );
124 }
125
126 /*
127  * Subtitles
128  */
129
130 void GtkMenubarSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
131 {
132     GTKLANGTOGGLE( p_popup, "popup_subpictures", SPU_ES,
133                    GtkPopupSubtitleToggle, b_spu_update );
134 }
135
136 void GtkPopupSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
137 {
138     GTKLANGTOGGLE( p_window, "menubar_subpictures", SPU_ES,
139                    GtkMenubarSubtitleToggle, b_spu_update );
140 }
141
142 #undef GTKLANGTOGGLE
143
144 /*
145  * Navigation
146  */
147
148 void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
149                                gpointer user_data )
150 {
151     intf_thread_t * p_intf = GtkGetIntf( menuitem );
152
153     if( menuitem->active &&
154         !p_intf->p_sys->b_title_update &&
155         !p_intf->p_sys->b_chapter_update )
156     {
157         input_area_t   *p_area;
158
159         guint i_title   = DATA2TITLE( user_data );
160         guint i_chapter = DATA2CHAPTER( user_data );
161
162         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
163         p_area = p_intf->p_sys->p_input->stream.p_selected_area;
164
165         i_title = __MIN( i_title,
166                          p_intf->p_sys->p_input->stream.i_area_nb - 1 );
167         i_title = __MAX( i_title, 1 );
168
169         if( p_area != p_intf->p_sys->p_input->stream.pp_areas[i_title] )
170         {
171             p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];
172             p_intf->p_sys->b_title_update = VLC_TRUE;
173         }
174
175         i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );
176         i_chapter = __MAX( i_chapter, 1 );
177         p_area->i_part = i_chapter;
178
179         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
180
181         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
182
183         p_intf->p_sys->b_chapter_update = VLC_TRUE;
184         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
185         GtkSetupMenus( p_intf );
186         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
187
188         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
189     }
190 }
191
192 /*
193  * Program
194  */
195 #define GTKPROGRAMTOGGLE( )                                                 \
196     intf_thread_t * p_intf = GtkGetIntf( menuitem );                        \
197                                                                             \
198     if( menuitem->active && !p_intf->p_sys->b_program_update )              \
199     {                                                                       \
200         int i_program_id = (ptrdiff_t)user_data;                            \
201                                                                             \
202         input_ChangeProgram( p_intf->p_sys->p_input, i_program_id );        \
203                                                                             \
204         p_intf->p_sys->b_program_update = VLC_TRUE;                         \
205                                                                             \
206         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );      \
207         GtkSetupMenus( p_intf );                                            \
208         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );    \
209                                                                             \
210         p_intf->p_sys->b_program_update = VLC_FALSE;                        \
211                                                                             \
212         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );       \
213     }
214
215 void GtkMenubarProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
216 {
217     GTKPROGRAMTOGGLE( );
218 }
219
220 void GtkPopupProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
221 {
222     GTKPROGRAMTOGGLE( );
223 }
224
225 /*
226  * Title
227  */
228
229 void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
230 {
231     intf_thread_t * p_intf = GtkGetIntf( menuitem );
232
233     if( menuitem->active && !p_intf->p_sys->b_title_update )
234     {
235         guint i_title = (ptrdiff_t)user_data;
236
237         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
238         i_title = __MIN( i_title,
239                          p_intf->p_sys->p_input->stream.i_area_nb - 1 );
240         i_title = __MAX( i_title, 1 );
241         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
242
243         input_ChangeArea( p_intf->p_sys->p_input,
244                           p_intf->p_sys->p_input->stream.pp_areas[i_title] );
245
246         p_intf->p_sys->b_title_update = VLC_TRUE;
247         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
248         GtkSetupMenus( p_intf );
249         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
250         p_intf->p_sys->b_title_update = VLC_FALSE;
251
252         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
253     }
254 }
255
256 /*
257  * Chapter
258  */
259
260 void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
261 {
262     intf_thread_t * p_intf;
263     input_area_t *  p_area;
264     guint           i_chapter;
265     GtkWidget *     p_popup_menu;
266
267     p_intf    = GtkGetIntf( menuitem );
268     p_area    = p_intf->p_sys->p_input->stream.p_selected_area;
269     i_chapter = (ptrdiff_t)user_data;
270
271     if( menuitem->active && !p_intf->p_sys->b_chapter_update )
272     {
273         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
274         i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );
275         i_chapter = __MAX( i_chapter, 1 );
276         p_area->i_part = i_chapter;
277         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
278
279         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
280
281         p_intf->p_sys->b_chapter_update = VLC_TRUE;
282         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
283                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
284
285         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
286         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
287         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
288
289         p_intf->p_sys->b_chapter_update = VLC_FALSE;
290
291         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
292     }
293 }
294
295
296 static void GtkPopupObjectToggle( GtkCheckMenuItem * menuitem, gpointer user_data,
297                                   int i_object_type, char *psz_variable )
298 {
299     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
300     GtkLabel        *p_label;
301
302     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
303
304     if( menuitem->active && !p_intf->p_sys->b_aout_update && !p_intf->p_sys->b_vout_update )
305     {
306         vlc_object_t * p_obj;
307
308         p_obj = (vlc_object_t *)vlc_object_find( p_intf, i_object_type,
309                                                   FIND_ANYWHERE );
310         if( p_obj )
311         {
312             vlc_value_t val;
313
314             gtk_label_get( p_label, &val.psz_string );
315
316             if( var_Set( p_obj, psz_variable, val ) < 0 )
317             {
318                 msg_Warn( p_obj, "cannot set variable (%s)", val.psz_string );
319             }
320             vlc_object_release( p_obj );
321         }
322     }
323 }
324 static void GtkPopupAoutChannelsToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
325 {
326     GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_AOUT, "audio-channels" );
327 }
328
329 static void GtkPopupAoutDeviceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
330 {
331     GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_AOUT, "audio-device" );
332 }
333
334
335 static void GtkPopupVoutDeviceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
336 {
337     GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_VOUT, "video-device" );
338 }
339
340
341 static void GtkDeinterlaceUpdate( intf_thread_t *p_intf, char *psz_mode )
342 {
343     char *psz_filter;
344     unsigned int  i;
345
346     psz_filter = config_GetPsz( p_intf, "filter" );
347
348     if( !strcmp( psz_mode, "None" ) )
349     {
350         config_PutPsz( p_intf, "filter", "" );
351     }
352     else
353     {
354         if( !psz_filter || !*psz_filter )
355         {
356             config_PutPsz( p_intf, "filter", "deinterlace" );
357         }
358         else
359         {
360             if( strstr( psz_filter, "deinterlace" ) == NULL )
361             {
362                 psz_filter = realloc( psz_filter, strlen( psz_filter ) + 20 );
363                 strcat( psz_filter, ",deinterlace" );
364             }
365             config_PutPsz( p_intf, "filter", psz_filter );
366         }
367     }
368
369     if( psz_filter )
370         free( psz_filter );
371
372     /* now restart all video stream */
373     if( p_intf->p_sys->p_input )
374     {
375         vout_thread_t *p_vout;
376         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
377
378         /* Warn the vout we are about to change the filter chain */
379         p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
380                                   FIND_ANYWHERE );
381         if( p_vout )
382         {
383             p_vout->b_filter_change = VLC_TRUE;
384             vlc_object_release( p_vout );
385         }
386
387 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
388         /* create a set of language buttons and append them to the container */
389         for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
390         {
391             if( ( ES->i_cat == VIDEO_ES ) &&
392                     ES->p_decoder_fifo != NULL )
393             {
394                 input_UnselectES( p_intf->p_sys->p_input, ES );
395                 input_SelectES( p_intf->p_sys->p_input, ES );
396             }
397 #undef ES
398         }
399         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
400     }
401
402     if( strcmp( psz_mode, "None" ) )
403     {
404         vout_thread_t *p_vout;
405         p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
406                                   FIND_ANYWHERE );
407         if( p_vout )
408         {
409             vlc_value_t val;
410
411             val.psz_string = psz_mode;
412             if( var_Set( p_vout, "deinterlace-mode", val ) != VLC_SUCCESS )
413                 config_PutPsz( p_intf, "deinterlace-mode", psz_mode );
414
415             vlc_object_release( p_vout );
416         }
417         else
418             config_PutPsz( p_intf, "deinterlace-mode", psz_mode );
419
420     }
421 }
422
423 static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
424 {
425     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
426     GtkLabel        *p_label;
427     char            *psz_mode;
428     GtkWidget       *p_popup_menu;
429
430     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
431
432     if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
433     {
434         gtk_label_get( p_label, &psz_mode );
435         GtkDeinterlaceUpdate( p_intf, psz_mode );
436
437         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
438
439         p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
440                                      p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
441
442         GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
443
444         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
445
446     }
447 }
448
449 static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
450 {
451     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
452     GtkLabel        *p_label;
453     char            *psz_mode;
454     GtkWidget       *p_menubar_menu;
455
456     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
457
458     if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
459     {
460         gtk_label_get( p_label, &psz_mode );
461         GtkDeinterlaceUpdate( p_intf, psz_mode );
462
463         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
464
465         p_menubar_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
466                                      p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
467
468         GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
469
470         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
471     }
472 }
473
474 /****************************************************************************
475  * Functions to generate menus
476  ****************************************************************************/
477
478 /*****************************************************************************
479  * GtkRadioMenu: update interactive menus of the interface
480  *****************************************************************************
481  * Sets up menus with information from input
482  * Warning: since this function is designed to be called by management
483  * function, the interface lock has to be taken
484  *****************************************************************************/
485 static gint GtkRadioMenu( intf_thread_t * p_intf,
486                             GtkWidget * p_root, GSList * p_menu_group,
487                             char * psz_item_name,
488                             int i_start, int i_end, int i_selected,
489                      void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) )
490 {
491     char                psz_name[ GTK_MENU_LABEL_SIZE ];
492     GtkWidget *         p_menu;
493     GtkWidget *         p_submenu;
494     GtkWidget *         p_item_group;
495     GtkWidget *         p_item;
496     GtkWidget *         p_item_selected;
497     GSList *            p_group;
498     gint                i_item;
499
500     /* temporary hack to avoid blank menu when an open menu is removed */
501     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
502     {
503         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
504     }
505     /* removes previous menu */
506     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
507     gtk_widget_set_sensitive( p_root, FALSE );
508
509     p_item_group = NULL;
510     p_submenu = NULL;
511     p_item_selected = NULL;
512     p_group = p_menu_group;
513
514     p_menu = gtk_menu_new();
515     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
516
517     for( i_item = i_start ; i_item <= i_end ; i_item++ )
518     {
519         /* we group chapters in packets of ten for small screens */
520         if( ( i_item % 10 == i_start ) && ( i_end > i_start + 20 ) )
521         {
522             if( i_item != i_start )
523             {
524                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ),
525                                            p_submenu );
526                 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
527             }
528
529             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
530                       "%ss %d to %d", psz_item_name, i_item, i_item + 9 );
531             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
532             p_item_group = gtk_menu_item_new_with_label( psz_name );
533             gtk_widget_show( p_item_group );
534             p_submenu = gtk_menu_new();
535             gtk_object_set_data( GTK_OBJECT( p_submenu ), "p_intf", p_intf );
536         }
537
538         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d",
539                   psz_item_name, i_item );
540         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
541
542         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
543         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
544
545         if( i_selected == i_item )
546         {
547             p_item_selected = p_item;
548         }
549
550         gtk_widget_show( p_item );
551
552         /* setup signal hanling */
553         gtk_signal_connect( GTK_OBJECT( p_item ),
554                             "toggled",
555                             GTK_SIGNAL_FUNC( pf_toggle ),
556                             (gpointer)((long)(i_item)) );
557
558         if( i_end > i_start + 20 )
559         {
560             gtk_menu_append( GTK_MENU( p_submenu ), p_item );
561         }
562         else
563         {
564             gtk_menu_append( GTK_MENU( p_menu ), p_item );
565         }
566     }
567
568     if( i_end > i_start + 20 )
569     {
570         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
571         gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
572     }
573
574     /* link the new menu to the title menu item */
575     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
576
577     /* toggle currently selected chapter
578      * We have to release the lock since input_ToggleES needs it */
579     if( p_item_selected != NULL )
580     {
581         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ),
582                                         TRUE );
583     }
584
585     /* be sure that menu is sensitive, if there are several items */
586     if( i_end > i_start )
587     {
588         gtk_widget_set_sensitive( p_root, TRUE );
589     }
590
591     return TRUE;
592 }
593
594 /*****************************************************************************
595  * GtkProgramMenu: update the programs menu of the interface
596  *****************************************************************************
597  * Builds the program menu according to what have been found in the PAT
598  * by the input. Usefull for multi-programs streams such as DVB ones.
599  *****************************************************************************/
600 static gint GtkProgramMenu( gpointer            p_data,
601                             GtkWidget *         p_root,
602                             pgrm_descriptor_t * p_pgrm,
603                       void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
604 {
605     intf_thread_t *     p_intf;
606     GtkWidget *         p_menu;
607     GtkWidget *         p_item;
608     GtkWidget *         p_item_active;
609     GSList *            p_group;
610     char                psz_name[ GTK_MENU_LABEL_SIZE ];
611     guint               i;
612
613     /* cast */
614     p_intf = (intf_thread_t *)p_data;
615
616     /* temporary hack to avoid blank menu when an open menu is removed */
617     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
618     {
619         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
620     }
621     /* removes previous menu */
622     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
623     gtk_widget_set_sensitive( p_root, FALSE );
624
625     p_group = NULL;
626
627     /* menu container */
628     p_menu = gtk_menu_new();
629     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
630
631     p_item_active = NULL;
632
633     /* create a set of program buttons and append them to the container */
634     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_pgrm_number ; i++ )
635     {
636         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "id %d",
637             p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );
638         psz_name[GTK_MENU_LABEL_SIZE-1] = '\0';
639
640         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
641         p_group =
642             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
643
644         if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )
645         {
646             /* don't lose p_item when we append into menu */
647             p_item_active = p_item;
648         }
649
650         gtk_widget_show( p_item );
651
652         /* setup signal hanling */
653         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
654                         GTK_SIGNAL_FUNC( pf_toggle ),
655                         (gpointer)(ptrdiff_t)( p_intf->p_sys->p_input->
656                         stream.pp_programs[i]->i_number ) );
657
658         gtk_menu_append( GTK_MENU( p_menu ), p_item );
659     }
660
661     /* link the new menu to the menubar item */
662     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
663
664     /* activation will call signals so we can only do it
665      * when submenu is attached to menu - to get intf_window
666      * We have to release the lock since input_ToggleES needs it */
667     if( p_item_active != NULL )
668     {
669         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
670                                         TRUE );
671     }
672
673     /* be sure that menu is sensitive if more than 1 program */
674     if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )
675     {
676         gtk_widget_set_sensitive( p_root, TRUE );
677     }
678
679     return TRUE;
680 }
681
682 /*****************************************************************************
683  * GtkLanguageMenus: update interactive menus of the interface
684  *****************************************************************************
685  * Sets up menus with information from input:
686  *  -languages
687  *  -sub-pictures
688  * Warning: since this function is designed to be called by management
689  * function, the interface lock has to be taken
690  *****************************************************************************/
691 static gint GtkLanguageMenus( gpointer          p_data,
692                               GtkWidget *       p_root,
693                               es_descriptor_t * p_es,
694                               gint              i_cat,
695                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
696 {
697     intf_thread_t *     p_intf;
698     GtkWidget *         p_menu;
699     GtkWidget *         p_separator;
700     GtkWidget *         p_item;
701     GtkWidget *         p_item_active;
702     GSList *            p_group;
703     char                psz_name[ GTK_MENU_LABEL_SIZE ];
704     guint               i_item;
705     guint               i;
706
707     p_intf = (intf_thread_t *)p_data;
708
709     /* temporary hack to avoid blank menu when an open menu is removed */
710     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
711     {
712         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
713     }
714     /* removes previous menu */
715     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
716     gtk_widget_set_sensitive( p_root, FALSE );
717
718     p_group = NULL;
719
720     /* menu container */
721     p_menu = gtk_menu_new();
722     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
723
724     /* special case for "off" item */
725     snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("None") );
726     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
727
728     p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
729     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
730
731     gtk_widget_show( p_item );
732
733     /* signal hanling for off */
734     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
735                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
736
737     gtk_menu_append( GTK_MENU( p_menu ), p_item );
738
739     p_separator = gtk_menu_item_new();
740     gtk_widget_set_sensitive( p_separator, FALSE );
741     gtk_widget_show( p_separator );
742     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
743
744     p_item_active = NULL;
745     i_item = 0;
746
747     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
748
749 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
750     /* create a set of language buttons and append them to the container */
751     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
752     {
753         if( ( ES->i_cat == i_cat ) &&
754             ( !ES->p_pgrm ||
755               ES->p_pgrm ==
756                  p_intf->p_sys->p_input->stream.p_selected_program ) )
757         {
758             i_item++;
759             strcpy( psz_name,
760                     p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc );
761             if( psz_name[0] == '\0' )
762             {
763                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
764                           "Language %d", i_item );
765                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
766             }
767
768             p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
769             p_group =
770                 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
771
772             if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )
773             {
774                 /* don't lose p_item when we append into menu */
775                 p_item_active = p_item;
776             }
777
778             gtk_widget_show( p_item );
779
780             /* setup signal hanling */
781             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
782                             GTK_SIGNAL_FUNC( pf_toggle ),
783                             (gpointer)( p_intf->p_sys->p_input->stream.pp_es[i] ) );
784
785             gtk_menu_append( GTK_MENU( p_menu ), p_item );
786         }
787     }
788
789     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
790
791     /* link the new menu to the menubar item */
792     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
793
794     /* acitvation will call signals so we can only do it
795      * when submenu is attached to menu - to get intf_window
796      * We have to release the lock since input_ToggleES needs it */
797     if( p_item_active != NULL )
798     {
799         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
800                                         TRUE );
801     }
802
803     /* be sure that menu is sensitive if non empty */
804     if( i_item > 0 )
805     {
806         gtk_widget_set_sensitive( p_root, TRUE );
807     }
808
809     return TRUE;
810 }
811
812 /*****************************************************************************
813  * GtkTitleMenu: sets menus for titles and chapters selection
814  *****************************************************************************
815  * Generates two types of menus:
816  *  -simple list of titles
817  *  -cascaded lists of chapters for each title
818  *****************************************************************************/
819 static gint GtkTitleMenu( gpointer       p_data,
820                           GtkWidget *    p_navigation,
821                           void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
822 {
823     intf_thread_t *     p_intf;
824     char                psz_name[ GTK_MENU_LABEL_SIZE ];
825     GtkWidget *         p_title_menu;
826     GtkWidget *         p_title_submenu;
827     GtkWidget *         p_title_item;
828     GtkWidget *         p_item_active;
829     GtkWidget *         p_chapter_menu;
830     GtkWidget *         p_chapter_submenu;
831     GtkWidget *         p_title_menu_item;
832     GtkWidget *         p_chapter_menu_item;
833     GtkWidget *         p_item;
834     GSList *            p_title_group;
835     GSList *            p_chapter_group;
836     guint               i_title;
837     guint               i_chapter;
838     guint               i_title_nb;
839     guint               i_chapter_nb;
840
841     /* cast */
842     p_intf = (intf_thread_t*)p_data;
843
844     /* temporary hack to avoid blank menu when an open menu is removed */
845     if( GTK_MENU_ITEM(p_navigation)->submenu != NULL )
846     {
847         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) );
848     }
849     /* removes previous menu */
850     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) );
851     gtk_widget_set_sensitive( p_navigation, FALSE );
852
853     p_title_menu = gtk_menu_new();
854     p_title_group = NULL;
855     p_title_submenu = NULL;
856     p_title_menu_item = NULL;
857     p_chapter_group = NULL;
858     p_chapter_submenu = NULL;
859     p_chapter_menu_item = NULL;
860     p_item_active = NULL;
861     i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb - 1;
862
863     gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf );
864
865     /* loop on titles */
866     for( i_title = 1 ; i_title <= i_title_nb ; i_title++ )
867     {
868         /* we group titles in packets of ten for small screens */
869         if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )
870         {
871             if( i_title != 1 )
872             {
873                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
874                                            p_title_submenu );
875                 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
876             }
877
878             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
879                       "%d - %d", i_title, i_title + 9 );
880             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
881             p_title_menu_item = gtk_menu_item_new_with_label( psz_name );
882             gtk_widget_show( p_title_menu_item );
883             p_title_submenu = gtk_menu_new();
884             gtk_object_set_data( GTK_OBJECT( p_title_submenu ),
885                                  "p_intf", p_intf );
886         }
887
888         snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title,
889                   p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1);
890         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
891 #if 0
892         if( pf_toggle == on_menubar_title_toggle )
893         {
894             p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
895                                                            psz_name );
896             p_title_group =
897               gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
898
899             if( p_intf->p_sys->p_input->stream.pp_areas[i_title] ==
900                          p_intf->p_sys->p_input->stream.p_selected_area )
901             {
902                 p_item_active = p_title_item;
903             }
904
905             /* setup signal hanling */
906             gtk_signal_connect( GTK_OBJECT( p_title_item ),
907                      "toggled",
908                      GTK_SIGNAL_FUNC( pf_toggle ),
909                      (gpointer)(p_intf->p_sys->p_input->stream.pp_areas[i_title]) );
910
911             if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
912             {
913                 /* be sure that menu is sensitive */
914                 gtk_widget_set_sensitive( p_navigation, TRUE );
915             }
916         }
917         else
918 #endif
919         {
920             p_title_item = gtk_menu_item_new_with_label( psz_name );
921
922 #if 1
923             p_chapter_menu = gtk_menu_new();
924             gtk_object_set_data( GTK_OBJECT( p_chapter_menu ),
925                                  "p_intf", p_intf );
926             i_chapter_nb =
927                p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1;
928
929             for( i_chapter = 1 ; i_chapter <= i_chapter_nb ; i_chapter++ )
930             {
931                 /* we group chapters in packets of ten for small screens */
932                 if( ( i_chapter % 10 == 1 ) && ( i_chapter_nb > 20 ) )
933                 {
934                     if( i_chapter != 1 )
935                     {
936                         gtk_menu_item_set_submenu(
937                                     GTK_MENU_ITEM( p_chapter_menu_item ),
938                                     p_chapter_submenu );
939                         gtk_menu_append( GTK_MENU( p_chapter_menu ),
940                                          p_chapter_menu_item );
941                     }
942
943                     snprintf( psz_name, GTK_MENU_LABEL_SIZE,
944                               "%d - %d", i_chapter, i_chapter + 9 );
945                     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
946                     p_chapter_menu_item =
947                             gtk_menu_item_new_with_label( psz_name );
948                     gtk_widget_show( p_chapter_menu_item );
949                     p_chapter_submenu = gtk_menu_new();
950                     gtk_object_set_data( GTK_OBJECT( p_chapter_submenu ),
951                                          "p_intf", p_intf );
952                 }
953
954                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
955                           _("Chapter %d"), i_chapter );
956                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
957
958                 p_item = gtk_radio_menu_item_new_with_label(
959                                                 p_chapter_group, psz_name );
960                 p_chapter_group = gtk_radio_menu_item_group(
961                                                 GTK_RADIO_MENU_ITEM( p_item ) );
962                 gtk_widget_show( p_item );
963
964 #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]
965                 if( ( p_area ==
966                         p_intf->p_sys->p_input->stream.p_selected_area ) &&
967                     ( p_area->i_part == i_chapter ) )
968                 {
969                     p_item_active = p_item;
970                 }
971 #undef p_area
972
973                 /* setup signal hanling */
974                 gtk_signal_connect( GTK_OBJECT( p_item ),
975                            "toggled",
976                            GTK_SIGNAL_FUNC( pf_toggle ),
977                            (gpointer)POS2DATA( i_title, i_chapter ) );
978
979                 if( i_chapter_nb > 20 )
980                 {
981                     gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item );
982                 }
983                 else
984                 {
985                     gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
986                 }
987             }
988
989             if( i_chapter_nb > 20 )
990             {
991                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ),
992                                            p_chapter_submenu );
993                 gtk_menu_append( GTK_MENU( p_chapter_menu ),
994                                  p_chapter_menu_item );
995             }
996
997             /* link the new menu to the title menu item */
998             gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
999                                        p_chapter_menu );
1000
1001             if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb > 1 )
1002             {
1003                 /* be sure that menu is sensitive */
1004                 gtk_widget_set_sensitive( p_navigation, TRUE );
1005             }
1006 #else
1007             GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"),
1008                 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1,
1009                 1, i_title * 100,
1010                 p_intf->p_sys->p_input->stream.p_selected_area->i_part +
1011                 p_intf->p_sys->p_input->stream.p_selected_area->i_id *100,
1012                 pf_toggle );
1013
1014 #endif
1015         }
1016         gtk_widget_show( p_title_item );
1017
1018         if( i_title_nb > 20 )
1019         {
1020             gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item );
1021         }
1022         else
1023         {
1024             gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
1025         }
1026     }
1027
1028     if( i_title_nb > 20 )
1029     {
1030         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
1031                                    p_title_submenu );
1032         gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
1033     }
1034
1035     /* be sure that menu is sensitive */
1036     gtk_widget_set_sensitive( p_title_menu, TRUE );
1037
1038     /* link the new menu to the menubar item */
1039     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
1040
1041     /* Default selected chapter
1042      * We have to release the lock since input_ToggleES needs it */
1043     if( p_item_active != NULL )
1044     {
1045         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
1046                                         TRUE );
1047     }
1048 #if 0
1049     if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
1050     {
1051         /* be sure that menu is sensitive */
1052         gtk_widget_set_sensitive( p_navigation, TRUE );
1053     }
1054 #endif
1055
1056     return TRUE;
1057 }
1058
1059 /*****************************************************************************
1060  * GtkSetupVarMenu :
1061  *****************************************************************************
1062  *
1063  *****************************************************************************/
1064 static gint GtkSetupVarMenu( intf_thread_t * p_intf,
1065                              vlc_object_t * p_object,
1066                              GtkWidget *p_root,
1067                              char * psz_variable,
1068                              void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
1069 {
1070     vlc_value_t         val;
1071     char              * psz_value;
1072     GtkWidget *         p_menu;
1073     GSList *            p_group = NULL;
1074     GtkWidget *         p_item;
1075     GtkWidget *         p_item_active = NULL;
1076
1077     int                 i_item;
1078
1079      /* temporary hack to avoid blank menu when an open menu is removed */
1080     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
1081     {
1082         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
1083     }
1084     /* removes previous menu */
1085     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
1086     gtk_widget_set_sensitive( p_root, FALSE );
1087
1088     /* get the current value */
1089     if( var_Get( p_object, psz_variable, &val ) < 0 )
1090     {
1091         return FALSE;
1092     }
1093     psz_value = val.psz_string;
1094
1095     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST, &val ) < 0 )
1096     {
1097         free( psz_value );
1098         return FALSE;
1099     }
1100
1101     /* menu container */
1102     p_menu = gtk_menu_new();
1103     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
1104
1105     for( i_item = 0; i_item < val.p_list->i_count; i_item++ )
1106     {
1107         p_item = gtk_radio_menu_item_new_with_label( p_group,
1108                                                      val.p_list->p_values[i_item].psz_string );
1109         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
1110
1111         if( !strcmp( psz_value, val.p_list->p_values[i_item].psz_string ) )
1112         {
1113             p_item_active = p_item;
1114         }
1115
1116         gtk_widget_show( p_item );
1117
1118         /* signal hanling for off */
1119         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
1120                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
1121
1122         gtk_menu_append( GTK_MENU( p_menu ), p_item );
1123
1124     }
1125     /* link the new menu to the menubar item */
1126     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
1127
1128     if( p_item_active )
1129     {
1130         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (p_item_active), TRUE);
1131     }
1132
1133     if( val.p_list->i_count > 0 )
1134     {
1135         gtk_widget_set_sensitive( p_root, TRUE );
1136     }
1137
1138     /* clean up everything */
1139     var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val );
1140
1141     return TRUE;
1142 }
1143
1144 /*****************************************************************************
1145  * GtkDeinterlaceMenus: update interactive menus of the interface
1146  *****************************************************************************
1147  *****************************************************************************/
1148 static gint GtkDeinterlaceMenus( gpointer          p_data,
1149                                  GtkWidget *       p_root,
1150                                  void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
1151 {
1152     intf_thread_t *     p_intf;
1153     GtkWidget *         p_menu;
1154     GtkWidget *         p_separator;
1155     GtkWidget *         p_item;
1156     GtkWidget *         p_item_active;
1157     GSList *            p_group;
1158     guint               i_item;
1159     guint               i;
1160     char                *ppsz_deinterlace_mode[] = { "discard", "blend", "mean", "bob", "linear", NULL };
1161     char                *psz_deinterlace_option;
1162     char                *psz_filter;
1163
1164     p_intf = (intf_thread_t *)p_data;
1165
1166     /* temporary hack to avoid blank menu when an open menu is removed */
1167     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
1168     {
1169         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
1170     }
1171     /* removes previous menu */
1172     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
1173     gtk_widget_set_sensitive( p_root, FALSE );
1174
1175     p_group = NULL;
1176
1177     /* menu container */
1178     p_menu = gtk_menu_new();
1179     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
1180
1181     /* special case for "off" item */
1182     p_item = gtk_radio_menu_item_new_with_label( p_group, "None" );
1183     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
1184
1185     gtk_widget_show( p_item );
1186
1187     /* signal hanling for off */
1188     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
1189                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
1190
1191     gtk_menu_append( GTK_MENU( p_menu ), p_item );
1192
1193     p_separator = gtk_menu_item_new();
1194     gtk_widget_set_sensitive( p_separator, FALSE );
1195     gtk_widget_show( p_separator );
1196     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
1197
1198
1199     /* search actual deinterlace mode */
1200     psz_filter = config_GetPsz( p_intf, "filter" );
1201     psz_deinterlace_option = strdup( "None" );
1202
1203     if( psz_filter && *psz_filter )
1204     {
1205        if( strstr ( psz_filter, "deinterlace" ) )
1206        {
1207             vlc_value_t val;
1208             vout_thread_t *p_vout;
1209
1210             p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
1211                                       FIND_ANYWHERE );
1212             if( p_vout &&
1213                 var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
1214             {
1215                 if( val.psz_string && *val.psz_string )
1216                 {
1217                     free( psz_deinterlace_option );
1218                     psz_deinterlace_option = val.psz_string;
1219                 }
1220                 else if( val.psz_string ) free( val.psz_string );
1221             }
1222
1223             if( p_vout ) vlc_object_release( p_vout );
1224        }
1225     }
1226     if( psz_filter )
1227         free( psz_filter );
1228
1229     p_item_active = NULL;
1230     i_item = 0;
1231
1232     /* create a set of deinteralce buttons and append them to the container */
1233     for( i = 0; ppsz_deinterlace_mode[i] != NULL; i++ )
1234     {
1235         i_item++;
1236
1237         p_item = gtk_radio_menu_item_new_with_label( p_group, ppsz_deinterlace_mode[i] );
1238         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
1239         gtk_widget_show( p_item );
1240
1241         if( !strcmp( ppsz_deinterlace_mode[i], psz_deinterlace_option ) )
1242         {
1243             p_item_active = p_item;
1244         }
1245         /* setup signal hanling */
1246         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
1247                             GTK_SIGNAL_FUNC( pf_toggle ),
1248                             NULL );
1249
1250         gtk_menu_append( GTK_MENU( p_menu ), p_item );
1251
1252     }
1253
1254     /* link the new menu to the menubar item */
1255     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
1256
1257     /* acitvation will call signals so we can only do it
1258      * when submenu is attached to menu - to get intf_window
1259      * We have to release the lock since input_ToggleES needs it */
1260     if( p_item_active != NULL )
1261     {
1262         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
1263                                         TRUE );
1264     }
1265
1266     /* be sure that menu is sensitive if non empty */
1267     if( i_item > 0 )
1268     {
1269         gtk_widget_set_sensitive( p_root, TRUE );
1270     }
1271
1272     return TRUE;
1273 }
1274
1275
1276
1277 /*****************************************************************************
1278  * GtkSetupMenus: function that generates title/chapter/audio/subpic
1279  * menus with help from preceding functions
1280  *****************************************************************************
1281  * Function called with the lock on stream
1282  *****************************************************************************/
1283 gint GtkSetupMenus( intf_thread_t * p_intf )
1284 {
1285     es_descriptor_t *   p_audio_es;
1286     es_descriptor_t *   p_spu_es;
1287     GtkWidget *         p_menubar_menu;
1288     GtkWidget *         p_popup_menu;
1289     guint               i;
1290
1291     p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
1292     p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |
1293                                      p_intf->p_sys->b_program_update;
1294     p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
1295                                    p_intf->p_sys->b_program_update;
1296
1297     if( 1 )
1298     {
1299         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1300                                      p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
1301         p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1302                                      p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
1303
1304         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
1305         GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
1306         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
1307         GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
1308
1309         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
1310     }
1311
1312     if( p_intf->p_sys->b_program_update )
1313     {
1314         pgrm_descriptor_t * p_pgrm;
1315
1316         if( p_intf->p_sys->p_input->stream.p_new_program )
1317         {
1318             p_pgrm = p_intf->p_sys->p_input->stream.p_new_program;
1319         }
1320         else
1321         {
1322             p_pgrm = p_intf->p_sys->p_input->stream.p_selected_program;
1323         }
1324
1325         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1326                             p_intf->p_sys->p_window ), "menubar_program" ) );
1327         GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm,
1328                         GtkMenubarProgramToggle );
1329
1330         p_intf->p_sys->b_program_update = VLC_TRUE;
1331         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1332                             p_intf->p_sys->p_popup ), "popup_program" ) );
1333         GtkProgramMenu( p_intf, p_popup_menu, p_pgrm,
1334                         GtkPopupProgramToggle );
1335
1336         p_intf->p_sys->b_program_update = VLC_FALSE;
1337     }
1338
1339     if( p_intf->p_sys->b_title_update )
1340     {
1341         char            psz_title[5];
1342
1343         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1344                             p_intf->p_sys->p_window ), "menubar_title" ) );
1345         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
1346                       p_intf->p_sys->p_input->stream.i_area_nb - 1,
1347                       p_intf->p_sys->p_input->stream.p_selected_area->i_id,
1348                       GtkMenubarTitleToggle );
1349
1350         snprintf( psz_title, 4, "%d",
1351                   p_intf->p_sys->p_input->stream.p_selected_area->i_id );
1352         psz_title[ 4 ] = '\0';
1353         gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
1354
1355         p_intf->p_sys->b_title_update = VLC_FALSE;
1356     }
1357
1358     if( p_intf->p_sys->b_chapter_update )
1359     {
1360         char            psz_chapter[5];
1361
1362         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1363                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
1364         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
1365 #if 0
1366         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
1367                         p_intf->p_sys->p_input->stream.i_area_nb - 1,
1368                         p_intf->p_sys->p_input->stream.p_selected_area->i_id,
1369                         on_menubar_chapter_toggle );
1370 #endif
1371
1372         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1373                              p_intf->p_sys->p_window ), "menubar_chapter" ) );
1374
1375         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"), 1,
1376                         p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb - 1,
1377                         p_intf->p_sys->p_input->stream.p_selected_area->i_part,
1378                         GtkMenubarChapterToggle );
1379
1380
1381         snprintf( psz_chapter, 4, "%d",
1382                   p_intf->p_sys->p_input->stream.p_selected_area->i_part );
1383         psz_chapter[ 4 ] = '\0';
1384         gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
1385
1386         p_intf->p_sys->i_part =
1387                 p_intf->p_sys->p_input->stream.p_selected_area->i_part;
1388
1389         p_intf->p_sys->b_chapter_update = VLC_FALSE;
1390     }
1391
1392     /* look for selected ES */
1393     p_audio_es = NULL;
1394     p_spu_es = NULL;
1395
1396     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ )
1397     {
1398         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
1399         {
1400             p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
1401         }
1402
1403         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
1404         {
1405             p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
1406         }
1407     }
1408
1409     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
1410
1411     /* audio menus */
1412     if( p_intf->p_sys->b_audio_update )
1413     {
1414         /* find audio root menu */
1415         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1416                              p_intf->p_sys->p_window ), "menubar_audio" ) );
1417
1418         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1419                      p_intf->p_sys->p_popup ), "popup_language" ) );
1420
1421         p_intf->p_sys->b_audio_update = VLC_TRUE;
1422         GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
1423                             GtkMenubarAudioToggle );
1424         p_intf->p_sys->b_audio_update = VLC_TRUE;
1425         GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
1426                             GtkPopupAudioToggle );
1427
1428         p_intf->p_sys->b_audio_update = VLC_FALSE;
1429     }
1430
1431     /* sub picture menus */
1432     if( p_intf->p_sys->b_spu_update )
1433     {
1434         /* find spu root menu */
1435         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1436                           p_intf->p_sys->p_window ), "menubar_subpictures" ) );
1437
1438         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1439                      p_intf->p_sys->p_popup ), "popup_subpictures" ) );
1440
1441         p_intf->p_sys->b_spu_update = VLC_TRUE;
1442         GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
1443                             GtkMenubarSubtitleToggle  );
1444         p_intf->p_sys->b_spu_update = VLC_TRUE;
1445         GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
1446                             GtkPopupSubtitleToggle );
1447
1448         p_intf->p_sys->b_spu_update = VLC_FALSE;
1449     }
1450     /* create audio channels and device menu (in menubar _and_ popup */
1451     if( p_intf->p_sys->b_aout_update )
1452     {
1453         aout_instance_t *p_aout;
1454
1455         p_aout = (aout_instance_t*)vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
1456
1457         if( p_aout != NULL )
1458         {
1459             vlc_value_t val;
1460             val.b_bool = VLC_FALSE;
1461
1462             var_Set( (vlc_object_t *)p_aout, "intf-change", val );
1463
1464             /* audio-channels */
1465             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1466                               p_intf->p_sys->p_window ), "menubar_audio_channels" ) );
1467             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1468                          p_intf->p_sys->p_popup ), "popup_audio_channels" ) );
1469             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
1470                               "audio-channels",  GtkPopupAoutChannelsToggle );
1471             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
1472                               "audio-channels",  GtkPopupAoutChannelsToggle );
1473
1474             /* audio-device */
1475             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1476                               p_intf->p_sys->p_window ), "menubar_audio_device" ) );
1477             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1478                          p_intf->p_sys->p_popup ), "popup_audio_device" ) );
1479             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
1480                               "audio-device",  GtkPopupAoutDeviceToggle );
1481             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
1482                               "audio-device",  GtkPopupAoutDeviceToggle );
1483
1484             vlc_object_release( (vlc_object_t *)p_aout );
1485         }
1486         p_intf->p_sys->b_aout_update = VLC_FALSE;
1487     }
1488
1489     if( p_intf->p_sys->b_vout_update )
1490     {
1491         vout_thread_t *p_vout;
1492
1493         p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
1494
1495         if( p_vout != NULL )
1496         {
1497             vlc_value_t val;
1498             val.b_bool = VLC_FALSE;
1499
1500             var_Set( (vlc_object_t *)p_vout, "intf-change", val );
1501
1502             /* video-device */
1503             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1504                               p_intf->p_sys->p_window ), "menubar_video_device" ) );
1505             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1506                          p_intf->p_sys->p_popup ), "popup_video_device" ) );
1507             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_popup_menu,
1508                               "video-device",  GtkPopupVoutDeviceToggle );
1509             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_menubar_menu,
1510                               "video-device",  GtkPopupVoutDeviceToggle );
1511
1512
1513             vlc_object_release( (vlc_object_t *)p_vout );
1514         }
1515         p_intf->p_sys->b_vout_update = VLC_FALSE;
1516     }
1517     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
1518
1519     return TRUE;
1520 }
1521