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