]> git.sesse.net Git - vlc/blob - plugins/gtk/gtk_menu.c
0ee02d7027eae1074065f6bf0b896a2d31d51e79
[vlc] / plugins / gtk / gtk_menu.c
1 /*****************************************************************************
2  * gtk_menu.c : functions to handle menu items.
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: gtk_menu.c,v 1.8 2001/05/31 16:10:05 stef Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Stéphane Borel <stef@via.ecp.fr>
9  *      
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29 #include <sys/types.h>                                              /* off_t */
30 #include <stdlib.h>
31
32 #include <gtk/gtk.h>
33
34 #include <string.h>
35
36 #include "config.h"
37 #include "common.h"
38 #include "threads.h"
39 #include "mtime.h"
40
41 #include "stream_control.h"
42 #include "input_ext-intf.h"
43
44 #include "interface.h"
45 #include "intf_playlist.h"
46 #include "intf_msg.h"
47
48 #include "video.h"
49 #include "video_output.h"
50 #include "audio_output.h"
51
52 #include "gtk_callbacks.h"
53 #include "gtk_interface.h"
54 #include "gtk_support.h"
55 #include "gtk_playlist.h"
56 #include "intf_gtk.h"
57
58 #include "main.h"
59
60 #include "modules_export.h"
61
62 /*
63  * Local Prototypes
64  */
65 static gint GtkLanguageMenus( gpointer , GtkWidget *, es_descriptor_t *, gint,
66                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
67
68 void GtkMenubarAudioToggle   ( GtkCheckMenuItem *, gpointer );
69 void GtkPopupAudioToggle     ( GtkCheckMenuItem *, gpointer );
70 void GtkMenubarSubtitleToggle( GtkCheckMenuItem *, gpointer );
71 void GtkPopupSubtitleToggle  ( GtkCheckMenuItem *, gpointer );
72 static gint GtkTitleMenu( gpointer, GtkWidget *, 
73                     void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
74 static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *,
75                           char *, int, int,
76                    void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) );
77 void GtkMenubarAngleToggle( GtkCheckMenuItem *, gpointer );
78 void GtkPopupAngleToggle( GtkCheckMenuItem *, gpointer );
79
80 gint GtkSetupMenus( intf_thread_t * p_intf );
81
82 /****************************************************************************
83  * Gtk*Toggle: callbacks to toggle the value of a checkmenuitem
84  ****************************************************************************
85  * We need separate functions for menubar and popup here since we can't use
86  * user_data to transmit intf_* and we need to refresh the other menu.
87  ****************************************************************************/
88
89 #define GtkLangToggle( intf, window, menu, type, callback, b_update )   \
90     intf_thread_t *         p_intf;                                     \
91     GtkWidget *             p_menu;                                     \
92     es_descriptor_t *       p_es;                                       \
93                                                                         \
94     p_intf = GetIntf( GTK_WIDGET(menuitem), (intf) );                   \
95                                                                         \
96     if( !p_intf->p_sys->b_update )                                      \
97     {                                                                   \
98         p_menu = GTK_WIDGET( gtk_object_get_data(                       \
99                    GTK_OBJECT( p_intf->p_sys->window ), (menu) ) );     \
100         p_es = (es_descriptor_t*)user_data;                             \
101                                                                         \
102         input_ToggleES( p_intf->p_input, p_es, menuitem->active );      \
103                                                                         \
104         p_intf->p_sys->b_update = menuitem->active;                     \
105                                                                         \
106         if( p_intf->p_sys->b_update )                                   \
107         {                                                               \
108             GtkLanguageMenus( p_intf, p_menu, p_es, type, callback );   \
109         }                                                               \
110                                                                         \
111         p_intf->p_sys->b_update = 0;                                    \
112     }
113
114 /*
115  * Audio
116  */ 
117
118 void GtkMenubarAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
119 {
120     GtkLangToggle( "intf_window", p_popup, "popup_audio", AUDIO_ES,
121                    GtkPopupAudioToggle, b_audio_update );
122 }
123
124 void GtkPopupAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
125 {
126     GtkLangToggle( "intf_popup", p_window, "menubar_audio", AUDIO_ES,
127                    GtkMenubarAudioToggle, b_audio_update );
128 }
129
130 /* 
131  * Subtitles
132  */ 
133
134 void GtkMenubarSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
135 {
136     GtkLangToggle( "intf_window", p_popup, "popup_subpictures", SPU_ES,
137                    GtkPopupSubtitleToggle, b_spu_update );
138 }
139
140 void GtkPopupSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
141 {
142     GtkLangToggle( "intf_popup", p_window, "menubar_subpictures", SPU_ES,
143                    GtkMenubarSubtitleToggle, b_spu_update );
144 }
145
146 #undef GtkLangToggle
147
148 /*
149  * Navigation
150  */
151
152 void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
153                                gpointer user_data )
154 {
155     intf_thread_t * p_intf = GetIntf( GTK_WIDGET(menuitem), "intf_popup" );
156
157     if( menuitem->active &&
158         !p_intf->p_sys->b_title_update &&
159         !p_intf->p_sys->b_chapter_update )
160     {
161         input_area_t   *p_area;
162
163         gint i_title   = DATA2TITLE( user_data );
164         gint i_chapter = DATA2CHAPTER( user_data );
165
166         p_area = p_intf->p_input->stream.p_selected_area;
167
168         if( p_area != p_intf->p_input->stream.pp_areas[i_title] )
169         {
170             p_area = p_intf->p_input->stream.pp_areas[i_title];
171             p_intf->p_sys->b_title_update = 1;
172         }
173
174         p_area->i_part = i_chapter;
175
176         input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );
177
178         p_intf->p_sys->b_chapter_update = 1;
179         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
180         GtkSetupMenus( p_intf );
181         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
182
183         input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
184     }
185 }
186
187 /*
188  * Title
189  */
190
191 void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
192 {
193     intf_thread_t * p_intf = GetIntf( GTK_WIDGET(menuitem), "intf_window" );
194
195     if( menuitem->active && !p_intf->p_sys->b_title_update )
196     {
197         gint i_title = (gint)user_data;
198         input_ChangeArea( p_intf->p_input,
199                           p_intf->p_input->stream.pp_areas[i_title] );
200
201         p_intf->p_sys->b_title_update = 1;
202         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
203         GtkSetupMenus( p_intf );
204         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
205         p_intf->p_sys->b_title_update = 0;
206
207         input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
208
209     }
210 }
211
212 /*
213  * Chapter
214  */
215
216 void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
217 {
218     intf_thread_t * p_intf;
219     input_area_t *  p_area;
220     gint            i_chapter;
221     char            psz_chapter[5];
222     GtkWidget *     p_popup_menu;
223
224     p_intf    = GetIntf( GTK_WIDGET(menuitem), "intf_window" );
225     p_area    = p_intf->p_input->stream.p_selected_area;
226     i_chapter = (gint)user_data;
227
228     if( menuitem->active && !p_intf->p_sys->b_chapter_update )
229     {
230         p_area->i_part = i_chapter;
231         input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );
232
233         snprintf( psz_chapter, 4, "%02d", p_area->i_part );
234         psz_chapter[ 4 ] = '\0';
235         gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
236
237         p_intf->p_sys->b_chapter_update = 1;
238         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
239                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
240
241         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
242         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
243         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
244
245         p_intf->p_sys->b_chapter_update = 0;
246
247         input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
248     }
249 }
250
251
252 /*
253  * Angle
254  */
255
256 #define GtkAngleToggle( intf, window, menu, callback )                      \
257     intf_thread_t * p_intf;                                                 \
258     GtkWidget *     p_menu;                                                 \
259     input_area_t *  p_area;                                                 \
260                                                                             \
261     p_intf    = GetIntf( GTK_WIDGET(menuitem), (intf) );                    \
262                                                                             \
263     if( menuitem->active && !p_intf->p_sys->b_angle_update )                \
264     {                                                                       \
265         p_menu    = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(            \
266                                 p_intf->p_sys->window ), (menu) ) );        \
267         p_area    = p_intf->p_input->stream.p_selected_area;                \
268         p_area->i_angle = (gint)user_data;                                  \
269                                                                             \
270         input_ChangeArea( p_intf->p_input, (input_area_t*)p_area );         \
271                                                                             \
272         p_intf->p_sys->b_angle_update = 1;                                  \
273         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );             \
274         GtkRadioMenu( p_intf, p_menu, NULL, "Angle",                        \
275                       p_area->i_angle_nb, p_area->i_angle, (callback) );    \
276         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );           \
277         p_intf->p_sys->b_angle_update = 0;                                  \
278     }
279
280 void GtkMenubarAngleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
281 {
282     GtkAngleToggle( "intf_window", p_popup, "popup_angle",
283                     GtkPopupAngleToggle );
284 }
285
286 void GtkPopupAngleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
287 {
288     GtkAngleToggle( "intf_popup", p_window, "menubar_angle",
289                     GtkMenubarAngleToggle );
290 }
291
292 #undef GtkAngleToggle
293
294 /****************************************************************************
295  * Functions to generate menus
296  ****************************************************************************/
297
298 /*****************************************************************************
299  * GtkRadioMenu: update interactive menus of the interface
300  *****************************************************************************
301  * Sets up menus with information from input
302  * Warning: since this function is designed to be called by management
303  * function, the interface lock has to be taken
304  *****************************************************************************/
305 static gint GtkRadioMenu( intf_thread_t * p_intf,
306                             GtkWidget * p_root, GSList * p_menu_group,
307                             char * psz_item_name,
308                             int i_nb, int i_selected,
309                      void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) )
310 {
311     char                psz_name[ GTK_MENU_LABEL_SIZE ];
312     GtkWidget *         p_menu;
313     GtkWidget *         p_submenu;
314     GtkWidget *         p_item_group;
315     GtkWidget *         p_item;
316     GtkWidget *         p_item_selected;
317     GSList *            p_group;
318     gint                i_item;
319
320     /* temporary hack to avoid blank menu when an open menu is removed */
321     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
322     {
323         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
324     }
325     /* removes previous menu */
326     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
327     gtk_widget_set_sensitive( p_root, FALSE );
328
329     p_item_group = NULL;
330     p_submenu = NULL;
331     p_item_selected = NULL;
332     p_group = p_menu_group;
333
334     p_menu = gtk_menu_new();
335
336     for( i_item = 0 ; i_item < i_nb ; i_item++ )
337     {
338         /* we group chapters in packets of ten for small screens */
339         if( ( i_item % 10 == 0 ) && ( i_nb > 20 ) )
340         {
341             if( i_item != 0 )
342             {
343                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ),
344                                            p_submenu );
345                 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
346             }
347
348             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
349                       "%ss %d to %d", psz_item_name, i_item + 1, i_item + 10);
350             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
351             p_item_group = gtk_menu_item_new_with_label( psz_name );
352             gtk_widget_show( p_item_group );
353             p_submenu = gtk_menu_new();
354         }
355
356         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d",
357                   psz_item_name, i_item + 1 );
358         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
359
360         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
361         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
362
363         if( i_selected == i_item + 1 )
364         {
365             p_item_selected = p_item;
366         }
367         
368         gtk_widget_show( p_item );
369
370         /* setup signal hanling */
371         gtk_signal_connect( GTK_OBJECT( p_item ),
372                             "toggled",
373                             GTK_SIGNAL_FUNC( pf_toggle ),
374                             (gpointer)(i_item + 1) );
375
376         if( i_nb > 20 )
377         {
378             gtk_menu_append( GTK_MENU( p_submenu ), p_item );
379         }
380         else
381         {
382             gtk_menu_append( GTK_MENU( p_menu ), p_item );
383         }
384     }
385
386     if( i_nb > 20 )
387     {
388         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
389         gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
390     }
391
392     /* link the new menu to the title menu item */
393     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
394
395     /* toggle currently selected chapter
396      * We have to release the lock since input_ToggleES needs it */
397     if( p_item_selected != NULL )
398     {
399         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
400         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ),
401                                         TRUE );
402         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
403     }
404
405     /* be sure that menu is sensitive, if there are several items */
406     if( i_nb > 1 )
407     {
408         gtk_widget_set_sensitive( p_root, TRUE );
409     }
410
411     return TRUE;
412 }
413
414 /*****************************************************************************
415  * GtkLanguageMenus: update interactive menus of the interface
416  *****************************************************************************
417  * Sets up menus with information from input:
418  *  -languages
419  *  -sub-pictures
420  * Warning: since this function is designed to be called by management
421  * function, the interface lock has to be taken
422  *****************************************************************************/
423 static gint GtkLanguageMenus( gpointer          p_data,
424                                 GtkWidget *       p_root,
425                                 es_descriptor_t * p_es,
426                                 gint              i_cat,
427                           void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
428 {
429     intf_thread_t *     p_intf;
430     GtkWidget *         p_menu;
431     GtkWidget *         p_separator;
432     GtkWidget *         p_item;
433     GtkWidget *         p_item_active;
434     GSList *            p_group;
435     char                psz_name[ GTK_MENU_LABEL_SIZE ];
436     gint                i_item;
437     gint                i;
438
439     
440
441     /* cast */
442     p_intf = (intf_thread_t *)p_data;
443
444     /* temporary hack to avoid blank menu when an open menu is removed */
445     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
446     {
447         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
448     }
449     /* removes previous menu */
450     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
451     gtk_widget_set_sensitive( p_root, FALSE );
452
453     p_group = NULL;
454
455     /* menu container */
456     p_menu = gtk_menu_new();
457
458     /* special case for "off" item */
459     snprintf( psz_name, GTK_MENU_LABEL_SIZE, "None" );
460     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
461
462     p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
463     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
464
465     gtk_widget_show( p_item );
466
467     /* signal hanling for off */
468     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
469                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
470
471     gtk_menu_append( GTK_MENU( p_menu ), p_item );
472
473     p_separator = gtk_menu_item_new();
474     gtk_widget_set_sensitive( p_separator, FALSE );
475     gtk_widget_show( p_separator );
476     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
477
478     p_item_active = NULL;
479     i_item = 0;
480
481     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
482
483     /* create a set of language buttons and append them to the container */
484     for( i = 0 ; i < p_intf->p_input->stream.i_es_number ; i++ )
485     {
486         if( p_intf->p_input->stream.pp_es[i]->i_cat == i_cat )
487         {
488             i_item++;
489             strcpy( psz_name, p_intf->p_input->stream.pp_es[i]->psz_desc );
490             if( psz_name[0] == '\0' )
491             {
492                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
493                           "Language %d", i_item );
494                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
495             }
496
497             p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
498             p_group =
499                 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
500
501             if( p_es == p_intf->p_input->stream.pp_es[i] )
502             {
503                 /* don't lose p_item when we append into menu */
504                 p_item_active = p_item;
505             }
506
507             gtk_widget_show( p_item );
508
509             /* setup signal hanling */
510             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
511                             GTK_SIGNAL_FUNC( pf_toggle ),
512                             (gpointer)( p_intf->p_input->stream.pp_es[i] ) );
513
514             gtk_menu_append( GTK_MENU( p_menu ), p_item );
515         }
516     }
517
518     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
519
520     /* link the new menu to the menubar item */
521     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
522
523     /* acitvation will call signals so we can only do it
524      * when submenu is attached to menu - to get intf_window 
525      * We have to release the lock since input_ToggleES needs it */
526     if( p_item_active != NULL )
527     {
528         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
529                                         TRUE );
530     }
531
532     /* be sure that menu is sensitive if non empty */
533     if( i_item > 0 )
534     {
535         gtk_widget_set_sensitive( p_root, TRUE );
536     }
537
538     return TRUE;
539 }
540
541 /*****************************************************************************
542  * GtkTitleMenu: sets menus for titles and chapters selection
543  *****************************************************************************
544  * Generates two types of menus:
545  *  -simple list of titles
546  *  -cascaded lists of chapters for each title
547  *****************************************************************************/
548 static gint GtkTitleMenu( gpointer       p_data,
549                             GtkWidget *    p_navigation, 
550                             void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
551 {
552     intf_thread_t *     p_intf;
553     char                psz_name[ GTK_MENU_LABEL_SIZE ];
554     GtkWidget *         p_title_menu;
555     GtkWidget *         p_title_submenu;
556     GtkWidget *         p_title_item;
557     GtkWidget *         p_item_active;
558     GtkWidget *         p_chapter_menu;
559     GtkWidget *         p_chapter_submenu;
560     GtkWidget *         p_title_menu_item;
561     GtkWidget *         p_chapter_menu_item;
562     GtkWidget *         p_item;
563     GSList *            p_title_group;
564     GSList *            p_chapter_group;
565     gint                i_title;
566     gint                i_chapter;
567     gint                i_title_nb;
568     gint                i_chapter_nb;
569
570     /* cast */
571     p_intf = (intf_thread_t*)p_data;
572
573     /* temporary hack to avoid blank menu when an open menu is removed */
574     if( GTK_MENU_ITEM(p_navigation)->submenu != NULL )
575     {
576         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) );
577     }
578     /* removes previous menu */
579     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) );
580     gtk_widget_set_sensitive( p_navigation, FALSE );
581
582     p_title_menu = gtk_menu_new();
583     p_title_group = NULL;
584     p_title_submenu = NULL;
585     p_title_menu_item = NULL;
586     p_chapter_group = NULL;
587     p_chapter_submenu = NULL;
588     p_chapter_menu_item = NULL;
589     p_item_active = NULL;
590     i_title_nb = p_intf->p_input->stream.i_area_nb;
591
592     /* loop on titles */
593     for( i_title = 1 ; i_title < i_title_nb ; i_title++ )
594     {
595         /* we group titles in packets of ten for small screens */
596         if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )
597         {
598             if( i_title != 1 )
599             {
600                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
601                                            p_title_submenu );
602                 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
603             }
604
605             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
606                       "%d - %d", i_title, i_title + 9 );
607             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
608             p_title_menu_item = gtk_menu_item_new_with_label( psz_name );
609             gtk_widget_show( p_title_menu_item );
610             p_title_submenu = gtk_menu_new();
611         }
612
613         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "Title %d (%d)", i_title,
614                   p_intf->p_input->stream.pp_areas[i_title]->i_part_nb );
615         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
616 #if 0
617         if( pf_toggle == on_menubar_title_toggle )
618         {
619             p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
620                                                            psz_name );
621             p_title_group =
622               gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
623
624             if( p_intf->p_input->stream.pp_areas[i_title] ==
625                          p_intf->p_input->stream.p_selected_area )
626             {
627                 p_item_active = p_title_item;
628             }
629
630             /* setup signal hanling */
631             gtk_signal_connect( GTK_OBJECT( p_title_item ),
632                      "toggled",
633                      GTK_SIGNAL_FUNC( pf_toggle ),
634                      (gpointer)(p_intf->p_input->stream.pp_areas[i_title]) );
635
636             if( p_intf->p_input->stream.i_area_nb > 1 )
637             {
638                 /* be sure that menu is sensitive */
639                 gtk_widget_set_sensitive( p_navigation, TRUE );
640             }
641         }
642         else
643 #endif
644         {
645             p_title_item = gtk_menu_item_new_with_label( psz_name );
646
647 #if 1    
648             p_chapter_menu = gtk_menu_new();
649             i_chapter_nb =
650                     p_intf->p_input->stream.pp_areas[i_title]->i_part_nb;
651     
652             for( i_chapter = 0 ; i_chapter < i_chapter_nb ; i_chapter++ )
653             {
654                 /* we group chapters in packets of ten for small screens */
655                 if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) )
656                 {
657                     if( i_chapter != 0 )
658                     {
659                         gtk_menu_item_set_submenu(
660                                     GTK_MENU_ITEM( p_chapter_menu_item ),
661                                     p_chapter_submenu );
662                         gtk_menu_append( GTK_MENU( p_chapter_menu ),
663                                          p_chapter_menu_item );
664                     }
665
666                     snprintf( psz_name, GTK_MENU_LABEL_SIZE,
667                               "%d - %d", i_chapter + 1, i_chapter + 10 );
668                     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
669                     p_chapter_menu_item =
670                             gtk_menu_item_new_with_label( psz_name );
671                     gtk_widget_show( p_chapter_menu_item );
672                     p_chapter_submenu = gtk_menu_new();
673                 }
674
675                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
676                           "Chapter %d", i_chapter + 1 );
677                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
678     
679                 p_item = gtk_radio_menu_item_new_with_label(
680                                                 p_chapter_group, psz_name );
681                 p_chapter_group = gtk_radio_menu_item_group(
682                                                 GTK_RADIO_MENU_ITEM( p_item ) );
683                 gtk_widget_show( p_item );
684
685 #define p_area p_intf->p_input->stream.pp_areas[i_title]
686                 if( ( p_area == p_intf->p_input->stream.p_selected_area ) &&
687                     ( p_area->i_part == i_chapter + 1 ) )
688                 {
689                     p_item_active = p_item;
690                 }
691 #undef p_area
692
693                 /* setup signal hanling */
694                 gtk_signal_connect( GTK_OBJECT( p_item ),
695                            "toggled",
696                            GTK_SIGNAL_FUNC( pf_toggle ),
697                            (gpointer)POS2DATA( i_title, i_chapter + 1) );
698
699                 if( i_chapter_nb > 20 )
700                 {
701                     gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item );
702                 }
703                 else
704                 {
705                     gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
706                 }
707             }
708
709             if( i_chapter_nb > 20 )
710             {
711                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ),
712                                            p_chapter_submenu );
713                 gtk_menu_append( GTK_MENU( p_chapter_menu ),
714                                  p_chapter_menu_item );
715             }
716
717             /* link the new menu to the title menu item */
718             gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
719                                        p_chapter_menu );
720
721             if( p_intf->p_input->stream.pp_areas[i_title]->i_part_nb > 1 )
722             {
723                 /* be sure that menu is sensitive */
724                 gtk_widget_set_sensitive( p_navigation, TRUE );
725             }
726 #else
727         GtkRadioMenu( p_intf, p_title_item, p_chapter_group, "Chapter",
728                         p_intf->p_input->stream.pp_areas[i_title]->i_part_nb,
729                         i_title * 100,
730                         p_intf->p_input->stream.p_selected_area->i_part +
731                             p_intf->p_input->stream.p_selected_area->i_id *100,
732                         pf_toggle );
733
734 #endif
735         }
736         gtk_widget_show( p_title_item );
737
738         if( i_title_nb > 20 )
739         {
740             gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item );
741         }
742         else
743         {
744             gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
745         }
746     }
747
748     if( i_title_nb > 20 )
749     {
750         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
751                                    p_title_submenu );
752         gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
753     }
754
755     /* be sure that menu is sensitive */
756     gtk_widget_set_sensitive( p_title_menu, TRUE );
757
758     /* link the new menu to the menubar item */
759     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
760
761     /* Default selected chapter
762      * We have to release the lock since input_ToggleES needs it */
763     if( p_item_active != NULL )
764     {
765         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
766         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
767                                         TRUE );
768         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
769     }
770 #if 0
771     if( p_intf->p_input->stream.i_area_nb > 1 )
772     {
773         /* be sure that menu is sensitive */
774         gtk_widget_set_sensitive( p_navigation, TRUE );
775     }
776 #endif
777
778     return TRUE;
779 }
780
781 /*****************************************************************************
782  * GtkSetupMenus: function that generates title/chapter/audio/subpic
783  * menus with help from preceding functions
784  *****************************************************************************/
785 gint GtkSetupMenus( intf_thread_t * p_intf )
786 {
787     es_descriptor_t *   p_audio_es;
788     es_descriptor_t *   p_spu_es;
789     GtkWidget *         p_menubar_menu;
790     GtkWidget *         p_popup_menu;
791     gint                i;
792
793     p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
794     p_intf->p_sys->b_angle_update |= p_intf->p_sys->b_title_update;
795     p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update;
796     p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update;
797
798 //    vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
799
800     if( p_intf->p_sys->b_title_update )
801     { 
802         char            psz_title[5];
803
804         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
805                             p_intf->p_sys->p_window ), "menubar_title" ) );
806         GtkRadioMenu( p_intf, p_menubar_menu, NULL, "Title",
807                       p_intf->p_input->stream.i_area_nb - 1,
808                       p_intf->p_input->stream.p_selected_area->i_id,
809                       GtkMenubarTitleToggle );
810
811         snprintf( psz_title, 4, "%d",
812                   p_intf->p_input->stream.p_selected_area->i_id );
813         psz_title[ 4 ] = '\0';
814         gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
815
816         p_intf->p_sys->b_title_update = 0;
817     }
818
819     if( p_intf->p_sys->b_chapter_update )
820     {
821         char            psz_chapter[5];
822
823         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
824                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
825         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
826 #if 0
827         GtkRadioMenu( p_intf, p_menubar_menu, NULL, "Title",
828                         p_intf->p_input->stream.i_area_nb - 1,
829                         p_intf->p_input->stream.p_selected_area->i_id,
830                         on_menubar_chapter_toggle );
831 #endif
832
833         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
834                              p_intf->p_sys->p_window ), "menubar_chapter" ) );
835         GtkRadioMenu( p_intf, p_menubar_menu, NULL, "Chapter",
836                         p_intf->p_input->stream.p_selected_area->i_part_nb,
837                         p_intf->p_input->stream.p_selected_area->i_part,
838                         GtkMenubarChapterToggle );
839
840
841         snprintf( psz_chapter, 4, "%d", 
842                   p_intf->p_input->stream.p_selected_area->i_part );
843         psz_chapter[ 4 ] = '\0';
844         gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
845
846         p_intf->p_sys->i_part =
847                 p_intf->p_input->stream.p_selected_area->i_part;
848
849         p_intf->p_sys->b_chapter_update = 0;
850     }
851
852     if( p_intf->p_sys->b_angle_update )
853     {
854         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
855                              p_intf->p_sys->p_window ), "menubar_angle" ) );
856         GtkRadioMenu( p_intf, p_menubar_menu, NULL, "Angle",
857                         p_intf->p_input->stream.p_selected_area->i_angle_nb,
858                         p_intf->p_input->stream.p_selected_area->i_angle,
859                         GtkMenubarAngleToggle );
860
861         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
862                              p_intf->p_sys->p_popup ), "popup_angle" ) );
863         GtkRadioMenu( p_intf, p_popup_menu, NULL, "Angle",
864                         p_intf->p_input->stream.p_selected_area->i_angle_nb,
865                         p_intf->p_input->stream.p_selected_area->i_angle,
866                         GtkPopupAngleToggle );
867
868         p_intf->p_sys->b_angle_update = 0;
869     }
870     
871     /* look for selected ES */
872     p_audio_es = NULL;
873     p_spu_es = NULL;
874
875     for( i = 0 ; i < p_intf->p_input->stream.i_selected_es_number ; i++ )
876     {
877         if( p_intf->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
878         {
879             p_audio_es = p_intf->p_input->stream.pp_selected_es[i];
880         }
881
882         if( p_intf->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
883         {
884             p_spu_es = p_intf->p_input->stream.pp_selected_es[i];
885         }
886     }
887
888     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
889
890     /* audio menus */
891     if( p_intf->p_sys->b_audio_update )
892     {
893         /* find audio root menu */
894         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
895                              p_intf->p_sys->p_window ), "menubar_audio" ) );
896     
897         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
898                      p_intf->p_sys->p_popup ), "popup_audio" ) );
899     
900         p_intf->p_sys->b_audio_update = 1;
901         GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
902                             GtkMenubarAudioToggle );
903         p_intf->p_sys->b_audio_update = 1;
904         GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
905                             GtkPopupAudioToggle );
906     
907         p_intf->p_sys->b_audio_update = 0;
908     }
909     
910     /* sub picture menus */
911     if( p_intf->p_sys->b_spu_update )
912     {
913         /* find spu root menu */
914         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
915                           p_intf->p_sys->p_window ), "menubar_subpictures" ) );
916     
917         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
918                      p_intf->p_sys->p_popup ), "popup_subpictures" ) );
919     
920         p_intf->p_sys->b_spu_update = 1;
921         GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
922                             GtkMenubarSubtitleToggle  );
923         p_intf->p_sys->b_spu_update = 1;
924         GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
925                             GtkPopupSubtitleToggle );
926     
927         p_intf->p_sys->b_spu_update = 0;
928     }
929
930     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
931
932     return TRUE;
933 }
934