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