]> git.sesse.net Git - vlc/blob - modules/gui/gtk/menu.c
946bc5f03a0260ff3bd1f9053b1f32b8ff418bef
[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.5 2003/01/22 00:32:32 fenrir 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_audio", 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     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         config_PutPsz( p_intf, "deinterlace-mode", psz_mode );
369     }
370
371     if( psz_filter )
372         free( psz_filter );
373
374     /* now restart all video stream */
375     if( p_intf->p_sys->p_input )
376     {
377         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
378 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
379         /* create a set of language buttons and append them to the container */
380         for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
381         {
382             if( ( ES->i_cat == VIDEO_ES ) &&
383                     ES->p_decoder_fifo != NULL )
384             {
385                 input_UnselectES( p_intf->p_sys->p_input, ES );
386                 input_SelectES( p_intf->p_sys->p_input, ES );
387             }
388 #undef ES
389         }
390         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
391     }
392 }
393
394 static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
395 {
396     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
397     GtkLabel        *p_label;
398     char            *psz_mode;
399     GtkWidget       *p_popup_menu;
400
401     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
402
403     if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
404     {
405         gtk_label_get( p_label, &psz_mode );
406         GtkDeinterlaceUpdate( p_intf, psz_mode );
407
408         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
409
410         p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
411                                      p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
412
413         GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
414
415         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
416
417     }
418 }
419
420 static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
421 {
422     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
423     GtkLabel        *p_label;
424     char            *psz_mode;
425     GtkWidget       *p_menubar_menu;
426
427     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
428
429     if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
430     {
431         gtk_label_get( p_label, &psz_mode );
432         GtkDeinterlaceUpdate( p_intf, psz_mode );
433
434         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
435
436         p_menubar_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
437                                      p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
438
439         GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
440
441         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
442     }
443 }
444
445 /****************************************************************************
446  * Functions to generate menus
447  ****************************************************************************/
448
449 /*****************************************************************************
450  * GtkRadioMenu: update interactive menus of the interface
451  *****************************************************************************
452  * Sets up menus with information from input
453  * Warning: since this function is designed to be called by management
454  * function, the interface lock has to be taken
455  *****************************************************************************/
456 static gint GtkRadioMenu( intf_thread_t * p_intf,
457                             GtkWidget * p_root, GSList * p_menu_group,
458                             char * psz_item_name,
459                             int i_start, int i_end, int i_selected,
460                      void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) )
461 {
462     char                psz_name[ GTK_MENU_LABEL_SIZE ];
463     GtkWidget *         p_menu;
464     GtkWidget *         p_submenu;
465     GtkWidget *         p_item_group;
466     GtkWidget *         p_item;
467     GtkWidget *         p_item_selected;
468     GSList *            p_group;
469     gint                i_item;
470
471     /* temporary hack to avoid blank menu when an open menu is removed */
472     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
473     {
474         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
475     }
476     /* removes previous menu */
477     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
478     gtk_widget_set_sensitive( p_root, FALSE );
479
480     p_item_group = NULL;
481     p_submenu = NULL;
482     p_item_selected = NULL;
483     p_group = p_menu_group;
484
485     p_menu = gtk_menu_new();
486     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
487
488     for( i_item = i_start ; i_item <= i_end ; i_item++ )
489     {
490         /* we group chapters in packets of ten for small screens */
491         if( ( i_item % 10 == i_start ) && ( i_end > i_start + 20 ) )
492         {
493             if( i_item != i_start )
494             {
495                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ),
496                                            p_submenu );
497                 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
498             }
499
500             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
501                       "%ss %d to %d", psz_item_name, i_item, i_item + 9 );
502             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
503             p_item_group = gtk_menu_item_new_with_label( psz_name );
504             gtk_widget_show( p_item_group );
505             p_submenu = gtk_menu_new();
506             gtk_object_set_data( GTK_OBJECT( p_submenu ), "p_intf", p_intf );
507         }
508
509         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d",
510                   psz_item_name, i_item );
511         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
512
513         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
514         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
515
516         if( i_selected == i_item )
517         {
518             p_item_selected = p_item;
519         }
520
521         gtk_widget_show( p_item );
522
523         /* setup signal hanling */
524         gtk_signal_connect( GTK_OBJECT( p_item ),
525                             "toggled",
526                             GTK_SIGNAL_FUNC( pf_toggle ),
527                             (gpointer)((long)(i_item)) );
528
529         if( i_end > i_start + 20 )
530         {
531             gtk_menu_append( GTK_MENU( p_submenu ), p_item );
532         }
533         else
534         {
535             gtk_menu_append( GTK_MENU( p_menu ), p_item );
536         }
537     }
538
539     if( i_end > i_start + 20 )
540     {
541         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
542         gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
543     }
544
545     /* link the new menu to the title menu item */
546     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
547
548     /* toggle currently selected chapter
549      * We have to release the lock since input_ToggleES needs it */
550     if( p_item_selected != NULL )
551     {
552         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ),
553                                         TRUE );
554     }
555
556     /* be sure that menu is sensitive, if there are several items */
557     if( i_end > i_start )
558     {
559         gtk_widget_set_sensitive( p_root, TRUE );
560     }
561
562     return TRUE;
563 }
564
565 /*****************************************************************************
566  * GtkProgramMenu: update the programs menu of the interface
567  *****************************************************************************
568  * Builds the program menu according to what have been found in the PAT
569  * by the input. Usefull for multi-programs streams such as DVB ones.
570  *****************************************************************************/
571 static gint GtkProgramMenu( gpointer            p_data,
572                             GtkWidget *         p_root,
573                             pgrm_descriptor_t * p_pgrm,
574                       void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
575 {
576     intf_thread_t *     p_intf;
577     GtkWidget *         p_menu;
578     GtkWidget *         p_item;
579     GtkWidget *         p_item_active;
580     GSList *            p_group;
581     char                psz_name[ GTK_MENU_LABEL_SIZE ];
582     guint               i;
583
584     /* cast */
585     p_intf = (intf_thread_t *)p_data;
586
587     /* temporary hack to avoid blank menu when an open menu is removed */
588     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
589     {
590         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
591     }
592     /* removes previous menu */
593     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
594     gtk_widget_set_sensitive( p_root, FALSE );
595
596     p_group = NULL;
597
598     /* menu container */
599     p_menu = gtk_menu_new();
600     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
601
602     p_item_active = NULL;
603
604     /* create a set of program buttons and append them to the container */
605     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_pgrm_number ; i++ )
606     {
607         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "id %d",
608             p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );
609         psz_name[GTK_MENU_LABEL_SIZE-1] = '\0';
610
611         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
612         p_group =
613             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
614
615         if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )
616         {
617             /* don't lose p_item when we append into menu */
618             p_item_active = p_item;
619         }
620
621         gtk_widget_show( p_item );
622
623         /* setup signal hanling */
624         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
625                         GTK_SIGNAL_FUNC( pf_toggle ),
626                         (gpointer)(ptrdiff_t)( p_intf->p_sys->p_input->
627                         stream.pp_programs[i]->i_number ) );
628
629         gtk_menu_append( GTK_MENU( p_menu ), p_item );
630     }
631
632     /* link the new menu to the menubar item */
633     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
634
635     /* activation will call signals so we can only do it
636      * when submenu is attached to menu - to get intf_window
637      * We have to release the lock since input_ToggleES needs it */
638     if( p_item_active != NULL )
639     {
640         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
641                                         TRUE );
642     }
643
644     /* be sure that menu is sensitive if more than 1 program */
645     if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )
646     {
647         gtk_widget_set_sensitive( p_root, TRUE );
648     }
649
650     return TRUE;
651 }
652
653 /*****************************************************************************
654  * GtkLanguageMenus: update interactive menus of the interface
655  *****************************************************************************
656  * Sets up menus with information from input:
657  *  -languages
658  *  -sub-pictures
659  * Warning: since this function is designed to be called by management
660  * function, the interface lock has to be taken
661  *****************************************************************************/
662 static gint GtkLanguageMenus( gpointer          p_data,
663                               GtkWidget *       p_root,
664                               es_descriptor_t * p_es,
665                               gint              i_cat,
666                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
667 {
668     intf_thread_t *     p_intf;
669     GtkWidget *         p_menu;
670     GtkWidget *         p_separator;
671     GtkWidget *         p_item;
672     GtkWidget *         p_item_active;
673     GSList *            p_group;
674     char                psz_name[ GTK_MENU_LABEL_SIZE ];
675     guint               i_item;
676     guint               i;
677
678     p_intf = (intf_thread_t *)p_data;
679
680     /* temporary hack to avoid blank menu when an open menu is removed */
681     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
682     {
683         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
684     }
685     /* removes previous menu */
686     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
687     gtk_widget_set_sensitive( p_root, FALSE );
688
689     p_group = NULL;
690
691     /* menu container */
692     p_menu = gtk_menu_new();
693     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
694
695     /* special case for "off" item */
696     snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("None") );
697     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
698
699     p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
700     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
701
702     gtk_widget_show( p_item );
703
704     /* signal hanling for off */
705     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
706                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
707
708     gtk_menu_append( GTK_MENU( p_menu ), p_item );
709
710     p_separator = gtk_menu_item_new();
711     gtk_widget_set_sensitive( p_separator, FALSE );
712     gtk_widget_show( p_separator );
713     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
714
715     p_item_active = NULL;
716     i_item = 0;
717
718     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
719
720 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
721     /* create a set of language buttons and append them to the container */
722     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
723     {
724         if( ( ES->i_cat == i_cat ) &&
725             ( !ES->p_pgrm ||
726               ES->p_pgrm ==
727                  p_intf->p_sys->p_input->stream.p_selected_program ) )
728         {
729             i_item++;
730             strcpy( psz_name,
731                     p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc );
732             if( psz_name[0] == '\0' )
733             {
734                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
735                           "Language %d", i_item );
736                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
737             }
738
739             p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
740             p_group =
741                 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
742
743             if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )
744             {
745                 /* don't lose p_item when we append into menu */
746                 p_item_active = p_item;
747             }
748
749             gtk_widget_show( p_item );
750
751             /* setup signal hanling */
752             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
753                             GTK_SIGNAL_FUNC( pf_toggle ),
754                             (gpointer)( p_intf->p_sys->p_input->stream.pp_es[i] ) );
755
756             gtk_menu_append( GTK_MENU( p_menu ), p_item );
757         }
758     }
759
760     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
761
762     /* link the new menu to the menubar item */
763     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
764
765     /* acitvation will call signals so we can only do it
766      * when submenu is attached to menu - to get intf_window
767      * We have to release the lock since input_ToggleES needs it */
768     if( p_item_active != NULL )
769     {
770         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
771                                         TRUE );
772     }
773
774     /* be sure that menu is sensitive if non empty */
775     if( i_item > 0 )
776     {
777         gtk_widget_set_sensitive( p_root, TRUE );
778     }
779
780     return TRUE;
781 }
782
783 /*****************************************************************************
784  * GtkTitleMenu: sets menus for titles and chapters selection
785  *****************************************************************************
786  * Generates two types of menus:
787  *  -simple list of titles
788  *  -cascaded lists of chapters for each title
789  *****************************************************************************/
790 static gint GtkTitleMenu( gpointer       p_data,
791                           GtkWidget *    p_navigation,
792                           void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
793 {
794     intf_thread_t *     p_intf;
795     char                psz_name[ GTK_MENU_LABEL_SIZE ];
796     GtkWidget *         p_title_menu;
797     GtkWidget *         p_title_submenu;
798     GtkWidget *         p_title_item;
799     GtkWidget *         p_item_active;
800     GtkWidget *         p_chapter_menu;
801     GtkWidget *         p_chapter_submenu;
802     GtkWidget *         p_title_menu_item;
803     GtkWidget *         p_chapter_menu_item;
804     GtkWidget *         p_item;
805     GSList *            p_title_group;
806     GSList *            p_chapter_group;
807     guint               i_title;
808     guint               i_chapter;
809     guint               i_title_nb;
810     guint               i_chapter_nb;
811
812     /* cast */
813     p_intf = (intf_thread_t*)p_data;
814
815     /* temporary hack to avoid blank menu when an open menu is removed */
816     if( GTK_MENU_ITEM(p_navigation)->submenu != NULL )
817     {
818         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) );
819     }
820     /* removes previous menu */
821     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) );
822     gtk_widget_set_sensitive( p_navigation, FALSE );
823
824     p_title_menu = gtk_menu_new();
825     p_title_group = NULL;
826     p_title_submenu = NULL;
827     p_title_menu_item = NULL;
828     p_chapter_group = NULL;
829     p_chapter_submenu = NULL;
830     p_chapter_menu_item = NULL;
831     p_item_active = NULL;
832     i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb - 1;
833
834     gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf );
835
836     /* loop on titles */
837     for( i_title = 1 ; i_title <= i_title_nb ; i_title++ )
838     {
839         /* we group titles in packets of ten for small screens */
840         if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )
841         {
842             if( i_title != 1 )
843             {
844                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
845                                            p_title_submenu );
846                 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
847             }
848
849             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
850                       "%d - %d", i_title, i_title + 9 );
851             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
852             p_title_menu_item = gtk_menu_item_new_with_label( psz_name );
853             gtk_widget_show( p_title_menu_item );
854             p_title_submenu = gtk_menu_new();
855             gtk_object_set_data( GTK_OBJECT( p_title_submenu ),
856                                  "p_intf", p_intf );
857         }
858
859         snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title,
860                   p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1);
861         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
862 #if 0
863         if( pf_toggle == on_menubar_title_toggle )
864         {
865             p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
866                                                            psz_name );
867             p_title_group =
868               gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
869
870             if( p_intf->p_sys->p_input->stream.pp_areas[i_title] ==
871                          p_intf->p_sys->p_input->stream.p_selected_area )
872             {
873                 p_item_active = p_title_item;
874             }
875
876             /* setup signal hanling */
877             gtk_signal_connect( GTK_OBJECT( p_title_item ),
878                      "toggled",
879                      GTK_SIGNAL_FUNC( pf_toggle ),
880                      (gpointer)(p_intf->p_sys->p_input->stream.pp_areas[i_title]) );
881
882             if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
883             {
884                 /* be sure that menu is sensitive */
885                 gtk_widget_set_sensitive( p_navigation, TRUE );
886             }
887         }
888         else
889 #endif
890         {
891             p_title_item = gtk_menu_item_new_with_label( psz_name );
892
893 #if 1
894             p_chapter_menu = gtk_menu_new();
895             gtk_object_set_data( GTK_OBJECT( p_chapter_menu ),
896                                  "p_intf", p_intf );
897             i_chapter_nb =
898                p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1;
899
900             for( i_chapter = 1 ; i_chapter <= i_chapter_nb ; i_chapter++ )
901             {
902                 /* we group chapters in packets of ten for small screens */
903                 if( ( i_chapter % 10 == 1 ) && ( i_chapter_nb > 20 ) )
904                 {
905                     if( i_chapter != 1 )
906                     {
907                         gtk_menu_item_set_submenu(
908                                     GTK_MENU_ITEM( p_chapter_menu_item ),
909                                     p_chapter_submenu );
910                         gtk_menu_append( GTK_MENU( p_chapter_menu ),
911                                          p_chapter_menu_item );
912                     }
913
914                     snprintf( psz_name, GTK_MENU_LABEL_SIZE,
915                               "%d - %d", i_chapter, i_chapter + 9 );
916                     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
917                     p_chapter_menu_item =
918                             gtk_menu_item_new_with_label( psz_name );
919                     gtk_widget_show( p_chapter_menu_item );
920                     p_chapter_submenu = gtk_menu_new();
921                     gtk_object_set_data( GTK_OBJECT( p_chapter_submenu ),
922                                          "p_intf", p_intf );
923                 }
924
925                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
926                           _("Chapter %d"), i_chapter );
927                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
928
929                 p_item = gtk_radio_menu_item_new_with_label(
930                                                 p_chapter_group, psz_name );
931                 p_chapter_group = gtk_radio_menu_item_group(
932                                                 GTK_RADIO_MENU_ITEM( p_item ) );
933                 gtk_widget_show( p_item );
934
935 #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]
936                 if( ( p_area ==
937                         p_intf->p_sys->p_input->stream.p_selected_area ) &&
938                     ( p_area->i_part == i_chapter ) )
939                 {
940                     p_item_active = p_item;
941                 }
942 #undef p_area
943
944                 /* setup signal hanling */
945                 gtk_signal_connect( GTK_OBJECT( p_item ),
946                            "toggled",
947                            GTK_SIGNAL_FUNC( pf_toggle ),
948                            (gpointer)POS2DATA( i_title, i_chapter ) );
949
950                 if( i_chapter_nb > 20 )
951                 {
952                     gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item );
953                 }
954                 else
955                 {
956                     gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
957                 }
958             }
959
960             if( i_chapter_nb > 20 )
961             {
962                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ),
963                                            p_chapter_submenu );
964                 gtk_menu_append( GTK_MENU( p_chapter_menu ),
965                                  p_chapter_menu_item );
966             }
967
968             /* link the new menu to the title menu item */
969             gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
970                                        p_chapter_menu );
971
972             if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb > 1 )
973             {
974                 /* be sure that menu is sensitive */
975                 gtk_widget_set_sensitive( p_navigation, TRUE );
976             }
977 #else
978             GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"),
979                 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1,
980                 1, i_title * 100,
981                 p_intf->p_sys->p_input->stream.p_selected_area->i_part +
982                 p_intf->p_sys->p_input->stream.p_selected_area->i_id *100,
983                 pf_toggle );
984
985 #endif
986         }
987         gtk_widget_show( p_title_item );
988
989         if( i_title_nb > 20 )
990         {
991             gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item );
992         }
993         else
994         {
995             gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
996         }
997     }
998
999     if( i_title_nb > 20 )
1000     {
1001         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
1002                                    p_title_submenu );
1003         gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
1004     }
1005
1006     /* be sure that menu is sensitive */
1007     gtk_widget_set_sensitive( p_title_menu, TRUE );
1008
1009     /* link the new menu to the menubar item */
1010     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
1011
1012     /* Default selected chapter
1013      * We have to release the lock since input_ToggleES needs it */
1014     if( p_item_active != NULL )
1015     {
1016         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
1017                                         TRUE );
1018     }
1019 #if 0
1020     if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
1021     {
1022         /* be sure that menu is sensitive */
1023         gtk_widget_set_sensitive( p_navigation, TRUE );
1024     }
1025 #endif
1026
1027     return TRUE;
1028 }
1029
1030 /*****************************************************************************
1031  * GtkSetupVarMenu :
1032  *****************************************************************************
1033  *
1034  *****************************************************************************/
1035 static gint GtkSetupVarMenu( intf_thread_t * p_intf,
1036                              vlc_object_t * p_object,
1037                              GtkWidget *p_root,
1038                              char * psz_variable,
1039                              void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
1040 {
1041     vlc_value_t         val;
1042     char              * psz_value;
1043     GtkWidget *         p_menu;
1044     GSList *            p_group = NULL;
1045     GtkWidget *         p_item;
1046     GtkWidget *         p_item_active = NULL;
1047
1048     int                 i_item;
1049
1050      /* temporary hack to avoid blank menu when an open menu is removed */
1051     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
1052     {
1053         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
1054     }
1055     /* removes previous menu */
1056     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
1057     gtk_widget_set_sensitive( p_root, FALSE );
1058
1059     /* get the current value */
1060     if( var_Get( p_object, psz_variable, &val ) < 0 )
1061     {
1062         return FALSE;
1063     }
1064     psz_value = val.psz_string;
1065
1066     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST, &val ) < 0 )
1067     {
1068         free( psz_value );
1069         return FALSE;
1070     }
1071
1072     /* menu container */
1073     p_menu = gtk_menu_new();
1074     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
1075
1076     for( i_item = 0; i_item < val.p_list->i_count; i_item++ )
1077     {
1078         p_item = gtk_radio_menu_item_new_with_label( p_group,
1079                                                      val.p_list->p_values[i_item].psz_string );
1080         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
1081
1082         if( !strcmp( psz_value, val.p_list->p_values[i_item].psz_string ) )
1083         {
1084             p_item_active = p_item;
1085         }
1086
1087         gtk_widget_show( p_item );
1088
1089         /* signal hanling for off */
1090         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
1091                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
1092
1093         gtk_menu_append( GTK_MENU( p_menu ), p_item );
1094
1095     }
1096     /* link the new menu to the menubar item */
1097     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
1098
1099     if( p_item_active )
1100     {
1101         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (p_item_active), TRUE);
1102     }
1103
1104     if( val.p_list->i_count > 0 )
1105     {
1106         gtk_widget_set_sensitive( p_root, TRUE );
1107     }
1108
1109     /* clean up everything */
1110     var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val );
1111
1112     return TRUE;
1113 }
1114
1115 /*****************************************************************************
1116  * GtkDeinterlaceMenus: update interactive menus of the interface
1117  *****************************************************************************
1118  *****************************************************************************/
1119 static gint GtkDeinterlaceMenus( gpointer          p_data,
1120                                  GtkWidget *       p_root,
1121                                  void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
1122 {
1123     intf_thread_t *     p_intf;
1124     GtkWidget *         p_menu;
1125     GtkWidget *         p_separator;
1126     GtkWidget *         p_item;
1127     GtkWidget *         p_item_active;
1128     GSList *            p_group;
1129     guint               i_item;
1130     guint               i;
1131     char                *ppsz_deinterlace_mode[] = { "discard", "blend", "mean", "bob", "linear", NULL };
1132     char                *psz_deinterlace_option;
1133     char                *psz_filter;
1134
1135     p_intf = (intf_thread_t *)p_data;
1136
1137     /* temporary hack to avoid blank menu when an open menu is removed */
1138     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
1139     {
1140         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
1141     }
1142     /* removes previous menu */
1143     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
1144     gtk_widget_set_sensitive( p_root, FALSE );
1145
1146     p_group = NULL;
1147
1148     /* menu container */
1149     p_menu = gtk_menu_new();
1150     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
1151
1152     /* special case for "off" item */
1153     p_item = gtk_radio_menu_item_new_with_label( p_group, "None" );
1154     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
1155
1156     gtk_widget_show( p_item );
1157
1158     /* signal hanling for off */
1159     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
1160                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
1161
1162     gtk_menu_append( GTK_MENU( p_menu ), p_item );
1163
1164     p_separator = gtk_menu_item_new();
1165     gtk_widget_set_sensitive( p_separator, FALSE );
1166     gtk_widget_show( p_separator );
1167     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
1168
1169
1170     /* search actual deinterlace mode */
1171     psz_filter = config_GetPsz( p_intf, "filter" );
1172     psz_deinterlace_option = strdup( "None" );
1173
1174     if( psz_filter && *psz_filter )
1175     {
1176        if( strstr ( psz_filter, "deinterlace" ) )
1177        {
1178             free( psz_deinterlace_option );
1179             psz_deinterlace_option = config_GetPsz( p_intf, "deinterlace-mode" );
1180             if( !psz_deinterlace_option )
1181                 psz_deinterlace_option = strdup( "None" );
1182        }
1183     }
1184     if( psz_filter )
1185         free( psz_filter );
1186
1187     p_item_active = NULL;
1188     i_item = 0;
1189
1190     /* create a set of deinteralce buttons and append them to the container */
1191     for( i = 0; ppsz_deinterlace_mode[i] != NULL; i++ )
1192     {
1193         i_item++;
1194
1195         p_item = gtk_radio_menu_item_new_with_label( p_group, ppsz_deinterlace_mode[i] );
1196         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
1197         gtk_widget_show( p_item );
1198
1199         if( !strcmp( ppsz_deinterlace_mode[i], psz_deinterlace_option ) )
1200         {
1201             p_item_active = p_item;
1202         }
1203         /* setup signal hanling */
1204         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
1205                             GTK_SIGNAL_FUNC( pf_toggle ),
1206                             NULL );
1207
1208         gtk_menu_append( GTK_MENU( p_menu ), p_item );
1209
1210     }
1211
1212     /* link the new menu to the menubar item */
1213     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
1214
1215     /* acitvation will call signals so we can only do it
1216      * when submenu is attached to menu - to get intf_window
1217      * We have to release the lock since input_ToggleES needs it */
1218     if( p_item_active != NULL )
1219     {
1220         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
1221                                         TRUE );
1222     }
1223
1224     /* be sure that menu is sensitive if non empty */
1225     if( i_item > 0 )
1226     {
1227         gtk_widget_set_sensitive( p_root, TRUE );
1228     }
1229
1230     return TRUE;
1231 }
1232
1233
1234
1235 /*****************************************************************************
1236  * GtkSetupMenus: function that generates title/chapter/audio/subpic
1237  * menus with help from preceding functions
1238  *****************************************************************************
1239  * Function called with the lock on stream
1240  *****************************************************************************/
1241 gint GtkSetupMenus( intf_thread_t * p_intf )
1242 {
1243     es_descriptor_t *   p_audio_es;
1244     es_descriptor_t *   p_spu_es;
1245     GtkWidget *         p_menubar_menu;
1246     GtkWidget *         p_popup_menu;
1247     guint               i;
1248
1249     p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
1250     p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |
1251                                      p_intf->p_sys->b_program_update;
1252     p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
1253                                    p_intf->p_sys->b_program_update;
1254
1255     if( 1 )
1256     {
1257         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1258                                      p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
1259         p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1260                                      p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
1261
1262         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
1263         GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
1264         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
1265         GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
1266
1267         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
1268     }
1269
1270     if( p_intf->p_sys->b_program_update )
1271     {
1272         pgrm_descriptor_t * p_pgrm;
1273
1274         if( p_intf->p_sys->p_input->stream.p_new_program )
1275         {
1276             p_pgrm = p_intf->p_sys->p_input->stream.p_new_program;
1277         }
1278         else
1279         {
1280             p_pgrm = p_intf->p_sys->p_input->stream.p_selected_program;
1281         }
1282
1283         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1284                             p_intf->p_sys->p_window ), "menubar_program" ) );
1285         GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm,
1286                         GtkMenubarProgramToggle );
1287
1288         p_intf->p_sys->b_program_update = VLC_TRUE;
1289         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1290                             p_intf->p_sys->p_popup ), "popup_program" ) );
1291         GtkProgramMenu( p_intf, p_popup_menu, p_pgrm,
1292                         GtkPopupProgramToggle );
1293
1294         p_intf->p_sys->b_program_update = VLC_FALSE;
1295     }
1296
1297     if( p_intf->p_sys->b_title_update )
1298     {
1299         char            psz_title[5];
1300
1301         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1302                             p_intf->p_sys->p_window ), "menubar_title" ) );
1303         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
1304                       p_intf->p_sys->p_input->stream.i_area_nb - 1,
1305                       p_intf->p_sys->p_input->stream.p_selected_area->i_id,
1306                       GtkMenubarTitleToggle );
1307
1308         snprintf( psz_title, 4, "%d",
1309                   p_intf->p_sys->p_input->stream.p_selected_area->i_id );
1310         psz_title[ 4 ] = '\0';
1311         gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
1312
1313         p_intf->p_sys->b_title_update = VLC_FALSE;
1314     }
1315
1316     if( p_intf->p_sys->b_chapter_update )
1317     {
1318         char            psz_chapter[5];
1319
1320         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1321                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
1322         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
1323 #if 0
1324         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
1325                         p_intf->p_sys->p_input->stream.i_area_nb - 1,
1326                         p_intf->p_sys->p_input->stream.p_selected_area->i_id,
1327                         on_menubar_chapter_toggle );
1328 #endif
1329
1330         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1331                              p_intf->p_sys->p_window ), "menubar_chapter" ) );
1332
1333         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"), 1,
1334                         p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb - 1,
1335                         p_intf->p_sys->p_input->stream.p_selected_area->i_part,
1336                         GtkMenubarChapterToggle );
1337
1338
1339         snprintf( psz_chapter, 4, "%d",
1340                   p_intf->p_sys->p_input->stream.p_selected_area->i_part );
1341         psz_chapter[ 4 ] = '\0';
1342         gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
1343
1344         p_intf->p_sys->i_part =
1345                 p_intf->p_sys->p_input->stream.p_selected_area->i_part;
1346
1347         p_intf->p_sys->b_chapter_update = VLC_FALSE;
1348     }
1349
1350     /* look for selected ES */
1351     p_audio_es = NULL;
1352     p_spu_es = NULL;
1353
1354     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ )
1355     {
1356         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
1357         {
1358             p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
1359         }
1360
1361         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
1362         {
1363             p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
1364         }
1365     }
1366
1367     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
1368
1369     /* audio menus */
1370     if( p_intf->p_sys->b_audio_update )
1371     {
1372         /* find audio root menu */
1373         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1374                              p_intf->p_sys->p_window ), "menubar_audio" ) );
1375
1376         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1377                      p_intf->p_sys->p_popup ), "popup_audio" ) );
1378
1379         p_intf->p_sys->b_audio_update = VLC_TRUE;
1380         GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
1381                             GtkMenubarAudioToggle );
1382         p_intf->p_sys->b_audio_update = VLC_TRUE;
1383         GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
1384                             GtkPopupAudioToggle );
1385
1386         p_intf->p_sys->b_audio_update = VLC_FALSE;
1387     }
1388
1389     /* sub picture menus */
1390     if( p_intf->p_sys->b_spu_update )
1391     {
1392         /* find spu root menu */
1393         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1394                           p_intf->p_sys->p_window ), "menubar_subpictures" ) );
1395
1396         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1397                      p_intf->p_sys->p_popup ), "popup_subpictures" ) );
1398
1399         p_intf->p_sys->b_spu_update = VLC_TRUE;
1400         GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
1401                             GtkMenubarSubtitleToggle  );
1402         p_intf->p_sys->b_spu_update = VLC_TRUE;
1403         GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
1404                             GtkPopupSubtitleToggle );
1405
1406         p_intf->p_sys->b_spu_update = VLC_FALSE;
1407     }
1408     /* create audio channels and device menu (in menubar _and_ popup */
1409     if( p_intf->p_sys->b_aout_update )
1410     {
1411         aout_instance_t *p_aout;
1412
1413         p_aout = (aout_instance_t*)vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
1414
1415         if( p_aout != NULL )
1416         {
1417             vlc_value_t val;
1418             val.b_bool = VLC_FALSE;
1419
1420             var_Set( (vlc_object_t *)p_aout, "intf-change", val );
1421
1422             /* audio-channels */
1423             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1424                               p_intf->p_sys->p_window ), "menubar_audio_channels" ) );
1425             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1426                          p_intf->p_sys->p_popup ), "popup_audio_channels" ) );
1427             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
1428                               "audio-channels",  GtkPopupAoutChannelsToggle );
1429             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
1430                               "audio-channels",  GtkPopupAoutChannelsToggle );
1431
1432             /* audio-device */
1433             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1434                               p_intf->p_sys->p_window ), "menubar_audio_device" ) );
1435             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1436                          p_intf->p_sys->p_popup ), "popup_audio_device" ) );
1437             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
1438                               "audio-device",  GtkPopupAoutDeviceToggle );
1439             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
1440                               "audio-device",  GtkPopupAoutDeviceToggle );
1441
1442             vlc_object_release( (vlc_object_t *)p_aout );
1443         }
1444         p_intf->p_sys->b_aout_update = VLC_FALSE;
1445     }
1446
1447     if( p_intf->p_sys->b_vout_update )
1448     {
1449         vout_thread_t *p_vout;
1450
1451         p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
1452
1453         if( p_vout != NULL )
1454         {
1455             vlc_value_t val;
1456             val.b_bool = VLC_FALSE;
1457
1458             var_Set( (vlc_object_t *)p_vout, "intf-change", val );
1459
1460             /* video-device */
1461             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1462                               p_intf->p_sys->p_window ), "menubar_video_device" ) );
1463             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
1464                          p_intf->p_sys->p_popup ), "popup_video_device" ) );
1465             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_popup_menu,
1466                               "video-device",  GtkPopupVoutDeviceToggle );
1467             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_menubar_menu,
1468                               "video-device",  GtkPopupVoutDeviceToggle );
1469
1470
1471             vlc_object_release( (vlc_object_t *)p_vout );
1472         }
1473         p_intf->p_sys->b_vout_update = VLC_FALSE;
1474     }
1475     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
1476
1477     return TRUE;
1478 }
1479