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