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