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