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