1 /*****************************************************************************
2 * gtk_menu.c : functions to handle menu items.
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: gtk_menu.c,v 1.27 2002/07/11 19:28:13 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Stéphane Borel <stef@via.ecp.fr>
9 * Johan Bilien <jobi@via.ecp.fr>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <sys/types.h> /* off_t */
35 #ifdef MODULE_NAME_IS_gnome
43 #include "gtk_callbacks.h"
44 #include "gtk_interface.h"
45 #include "gtk_support.h"
46 #include "gtk_playlist.h"
47 #include "gtk_common.h"
52 static gint GtkLanguageMenus( gpointer , GtkWidget *, es_descriptor_t *, gint,
53 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
55 void GtkMenubarAudioToggle ( GtkCheckMenuItem *, gpointer );
56 void GtkPopupAudioToggle ( GtkCheckMenuItem *, gpointer );
57 void GtkMenubarSubtitleToggle( GtkCheckMenuItem *, gpointer );
58 void GtkPopupSubtitleToggle ( GtkCheckMenuItem *, gpointer );
59 static gint GtkTitleMenu( gpointer, GtkWidget *,
60 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
61 static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *,
63 void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) );
65 gint GtkSetupMenus( intf_thread_t * p_intf );
67 /****************************************************************************
68 * Gtk*Toggle: callbacks to toggle the value of a checkmenuitem
69 ****************************************************************************
70 * We need separate functions for menubar and popup here since we can't use
71 * user_data to transmit intf_* and we need to refresh the other menu.
72 ****************************************************************************/
74 #define GTKLANGTOGGLE( window, menu, type, callback, b_update ) \
75 intf_thread_t * p_intf; \
77 es_descriptor_t * p_es; \
79 p_intf = GtkGetIntf( menuitem ); \
81 if( !p_intf->p_sys->b_update ) \
83 p_menu = GTK_WIDGET( gtk_object_get_data( \
84 GTK_OBJECT( p_intf->p_sys->window ), (menu) ) ); \
85 p_es = (es_descriptor_t*)user_data; \
87 input_ToggleES( p_intf->p_sys->p_input, \
88 p_es, menuitem->active ); \
90 p_intf->p_sys->b_update = menuitem->active; \
92 if( p_intf->p_sys->b_update ) \
94 GtkLanguageMenus( p_intf, p_menu, p_es, type, callback ); \
97 p_intf->p_sys->b_update = 0; \
104 void GtkMenubarAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
106 GTKLANGTOGGLE( p_popup, "popup_audio", AUDIO_ES,
107 GtkPopupAudioToggle, b_audio_update );
110 void GtkPopupAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
112 GTKLANGTOGGLE( p_window, "menubar_audio", AUDIO_ES,
113 GtkMenubarAudioToggle, b_audio_update );
120 void GtkMenubarSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
122 GTKLANGTOGGLE( p_popup, "popup_subpictures", SPU_ES,
123 GtkPopupSubtitleToggle, b_spu_update );
126 void GtkPopupSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
128 GTKLANGTOGGLE( p_window, "menubar_subpictures", SPU_ES,
129 GtkMenubarSubtitleToggle, b_spu_update );
138 void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
141 intf_thread_t * p_intf = GtkGetIntf( menuitem );
143 if( menuitem->active &&
144 !p_intf->p_sys->b_title_update &&
145 !p_intf->p_sys->b_chapter_update )
147 input_area_t *p_area;
149 gint i_title = DATA2TITLE( user_data );
150 gint i_chapter = DATA2CHAPTER( user_data );
152 p_area = p_intf->p_sys->p_input->stream.p_selected_area;
154 if( p_area != p_intf->p_sys->p_input->stream.pp_areas[i_title] )
156 p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];
157 p_intf->p_sys->b_title_update = 1;
160 p_area->i_part = i_chapter;
162 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
164 p_intf->p_sys->b_chapter_update = 1;
165 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
166 GtkSetupMenus( p_intf );
167 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
169 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
176 #define GTKPROGRAMTOGGLE( ) \
177 intf_thread_t * p_intf = GtkGetIntf( menuitem ); \
179 if( menuitem->active && !p_intf->p_sys->b_program_update ) \
181 u16 i_program_id = (ptrdiff_t)user_data; \
183 input_ChangeProgram( p_intf->p_sys->p_input, i_program_id ); \
185 p_intf->p_sys->b_program_update = 1; \
187 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); \
188 GtkSetupMenus( p_intf ); \
189 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); \
191 p_intf->p_sys->b_program_update = 0; \
193 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); \
196 void GtkMenubarProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
201 void GtkPopupProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
210 void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
212 intf_thread_t * p_intf = GtkGetIntf( menuitem );
214 if( menuitem->active && !p_intf->p_sys->b_title_update )
216 gint i_title = (gint)((long)user_data);
217 input_ChangeArea( p_intf->p_sys->p_input,
218 p_intf->p_sys->p_input->stream.pp_areas[i_title] );
220 p_intf->p_sys->b_title_update = 1;
221 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
222 GtkSetupMenus( p_intf );
223 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
224 p_intf->p_sys->b_title_update = 0;
226 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
235 void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
237 intf_thread_t * p_intf;
238 input_area_t * p_area;
240 GtkWidget * p_popup_menu;
242 p_intf = GtkGetIntf( menuitem );
243 p_area = p_intf->p_sys->p_input->stream.p_selected_area;
244 i_chapter = (gint)((long)user_data);
246 if( menuitem->active && !p_intf->p_sys->b_chapter_update )
248 p_area->i_part = i_chapter;
249 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
251 p_intf->p_sys->b_chapter_update = 1;
252 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
253 p_intf->p_sys->p_popup ), "popup_navigation" ) );
255 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
256 GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
257 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
259 p_intf->p_sys->b_chapter_update = 0;
261 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
266 /****************************************************************************
267 * Functions to generate menus
268 ****************************************************************************/
270 /*****************************************************************************
271 * GtkRadioMenu: update interactive menus of the interface
272 *****************************************************************************
273 * Sets up menus with information from input
274 * Warning: since this function is designed to be called by management
275 * function, the interface lock has to be taken
276 *****************************************************************************/
277 static gint GtkRadioMenu( intf_thread_t * p_intf,
278 GtkWidget * p_root, GSList * p_menu_group,
279 char * psz_item_name,
280 int i_nb, int i_selected,
281 void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) )
283 char psz_name[ GTK_MENU_LABEL_SIZE ];
285 GtkWidget * p_submenu;
286 GtkWidget * p_item_group;
288 GtkWidget * p_item_selected;
292 /* temporary hack to avoid blank menu when an open menu is removed */
293 if( GTK_MENU_ITEM(p_root)->submenu != NULL )
295 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
297 /* removes previous menu */
298 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
299 gtk_widget_set_sensitive( p_root, FALSE );
303 p_item_selected = NULL;
304 p_group = p_menu_group;
306 p_menu = gtk_menu_new();
307 gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
309 for( i_item = 0 ; i_item < i_nb ; i_item++ )
311 /* we group chapters in packets of ten for small screens */
312 if( ( i_item % 10 == 0 ) && ( i_nb > 20 ) )
316 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ),
318 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
321 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
322 "%ss %d to %d", psz_item_name, i_item + 1, i_item + 10);
323 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
324 p_item_group = gtk_menu_item_new_with_label( psz_name );
325 gtk_widget_show( p_item_group );
326 p_submenu = gtk_menu_new();
327 gtk_object_set_data( GTK_OBJECT( p_submenu ), "p_intf", p_intf );
330 snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d",
331 psz_item_name, i_item + 1 );
332 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
334 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
335 p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
337 if( i_selected == i_item + 1 )
339 p_item_selected = p_item;
342 gtk_widget_show( p_item );
344 /* setup signal hanling */
345 gtk_signal_connect( GTK_OBJECT( p_item ),
347 GTK_SIGNAL_FUNC( pf_toggle ),
348 (gpointer)((long)(i_item + 1)) );
352 gtk_menu_append( GTK_MENU( p_submenu ), p_item );
356 gtk_menu_append( GTK_MENU( p_menu ), p_item );
362 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
363 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
366 /* link the new menu to the title menu item */
367 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
369 /* toggle currently selected chapter
370 * We have to release the lock since input_ToggleES needs it */
371 if( p_item_selected != NULL )
373 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ),
377 /* be sure that menu is sensitive, if there are several items */
380 gtk_widget_set_sensitive( p_root, TRUE );
386 /*****************************************************************************
387 * GtkProgramMenu: update the programs menu of the interface
388 *****************************************************************************
389 * Builds the program menu according to what have been found in the PAT
390 * by the input. Usefull for multi-programs streams such as DVB ones.
391 *****************************************************************************/
392 static gint GtkProgramMenu( gpointer p_data,
394 pgrm_descriptor_t * p_pgrm,
395 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
397 intf_thread_t * p_intf;
400 GtkWidget * p_item_active;
402 char psz_name[ GTK_MENU_LABEL_SIZE ];
406 p_intf = (intf_thread_t *)p_data;
408 /* temporary hack to avoid blank menu when an open menu is removed */
409 if( GTK_MENU_ITEM(p_root)->submenu != NULL )
411 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
413 /* removes previous menu */
414 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
415 gtk_widget_set_sensitive( p_root, FALSE );
420 p_menu = gtk_menu_new();
421 gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
423 p_item_active = NULL;
425 /* create a set of program buttons and append them to the container */
426 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_pgrm_number ; i++ )
428 snprintf( psz_name, GTK_MENU_LABEL_SIZE, "id %d",
429 p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );
430 psz_name[GTK_MENU_LABEL_SIZE-1] = '\0';
432 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
434 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
436 if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )
438 /* don't lose p_item when we append into menu */
439 p_item_active = p_item;
442 gtk_widget_show( p_item );
444 /* setup signal hanling */
445 gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
446 GTK_SIGNAL_FUNC( pf_toggle ),
447 (gpointer)(ptrdiff_t)( p_intf->p_sys->p_input->
448 stream.pp_programs[i]->i_number ) );
450 gtk_menu_append( GTK_MENU( p_menu ), p_item );
453 /* link the new menu to the menubar item */
454 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
456 /* activation will call signals so we can only do it
457 * when submenu is attached to menu - to get intf_window
458 * We have to release the lock since input_ToggleES needs it */
459 if( p_item_active != NULL )
461 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
465 /* be sure that menu is sensitive if more than 1 program */
466 if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )
468 gtk_widget_set_sensitive( p_root, TRUE );
474 /*****************************************************************************
475 * GtkLanguageMenus: update interactive menus of the interface
476 *****************************************************************************
477 * Sets up menus with information from input:
480 * Warning: since this function is designed to be called by management
481 * function, the interface lock has to be taken
482 *****************************************************************************/
483 static gint GtkLanguageMenus( gpointer p_data,
485 es_descriptor_t * p_es,
487 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
489 intf_thread_t * p_intf;
491 GtkWidget * p_separator;
493 GtkWidget * p_item_active;
495 char psz_name[ GTK_MENU_LABEL_SIZE ];
499 p_intf = (intf_thread_t *)p_data;
501 /* temporary hack to avoid blank menu when an open menu is removed */
502 if( GTK_MENU_ITEM(p_root)->submenu != NULL )
504 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
506 /* removes previous menu */
507 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
508 gtk_widget_set_sensitive( p_root, FALSE );
513 p_menu = gtk_menu_new();
514 gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
516 /* special case for "off" item */
517 snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("None") );
518 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
520 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
521 p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
523 gtk_widget_show( p_item );
525 /* signal hanling for off */
526 gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
527 GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
529 gtk_menu_append( GTK_MENU( p_menu ), p_item );
531 p_separator = gtk_menu_item_new();
532 gtk_widget_set_sensitive( p_separator, FALSE );
533 gtk_widget_show( p_separator );
534 gtk_menu_append( GTK_MENU( p_menu ), p_separator );
536 p_item_active = NULL;
539 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
541 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
542 /* create a set of language buttons and append them to the container */
543 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
545 if( ( ES->i_cat == i_cat ) &&
548 p_intf->p_sys->p_input->stream.p_selected_program ) )
552 p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc );
553 if( psz_name[0] == '\0' )
555 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
556 "Language %d", i_item );
557 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
560 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
562 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
564 if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )
566 /* don't lose p_item when we append into menu */
567 p_item_active = p_item;
570 gtk_widget_show( p_item );
572 /* setup signal hanling */
573 gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
574 GTK_SIGNAL_FUNC( pf_toggle ),
575 (gpointer)( p_intf->p_sys->p_input->stream.pp_es[i] ) );
577 gtk_menu_append( GTK_MENU( p_menu ), p_item );
581 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
583 /* link the new menu to the menubar item */
584 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
586 /* acitvation will call signals so we can only do it
587 * when submenu is attached to menu - to get intf_window
588 * We have to release the lock since input_ToggleES needs it */
589 if( p_item_active != NULL )
591 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
595 /* be sure that menu is sensitive if non empty */
598 gtk_widget_set_sensitive( p_root, TRUE );
604 /*****************************************************************************
605 * GtkTitleMenu: sets menus for titles and chapters selection
606 *****************************************************************************
607 * Generates two types of menus:
608 * -simple list of titles
609 * -cascaded lists of chapters for each title
610 *****************************************************************************/
611 static gint GtkTitleMenu( gpointer p_data,
612 GtkWidget * p_navigation,
613 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
615 intf_thread_t * p_intf;
616 char psz_name[ GTK_MENU_LABEL_SIZE ];
617 GtkWidget * p_title_menu;
618 GtkWidget * p_title_submenu;
619 GtkWidget * p_title_item;
620 GtkWidget * p_item_active;
621 GtkWidget * p_chapter_menu;
622 GtkWidget * p_chapter_submenu;
623 GtkWidget * p_title_menu_item;
624 GtkWidget * p_chapter_menu_item;
626 GSList * p_title_group;
627 GSList * p_chapter_group;
634 p_intf = (intf_thread_t*)p_data;
636 /* temporary hack to avoid blank menu when an open menu is removed */
637 if( GTK_MENU_ITEM(p_navigation)->submenu != NULL )
639 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) );
641 /* removes previous menu */
642 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) );
643 gtk_widget_set_sensitive( p_navigation, FALSE );
645 p_title_menu = gtk_menu_new();
646 p_title_group = NULL;
647 p_title_submenu = NULL;
648 p_title_menu_item = NULL;
649 p_chapter_group = NULL;
650 p_chapter_submenu = NULL;
651 p_chapter_menu_item = NULL;
652 p_item_active = NULL;
653 i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb;
655 gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf );
658 for( i_title = 1 ; i_title < i_title_nb ; i_title++ )
660 /* we group titles in packets of ten for small screens */
661 if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )
665 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
667 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
670 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
671 "%d - %d", i_title, i_title + 9 );
672 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
673 p_title_menu_item = gtk_menu_item_new_with_label( psz_name );
674 gtk_widget_show( p_title_menu_item );
675 p_title_submenu = gtk_menu_new();
676 gtk_object_set_data( GTK_OBJECT( p_title_submenu ),
680 snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title,
681 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb );
682 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
684 if( pf_toggle == on_menubar_title_toggle )
686 p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
689 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
691 if( p_intf->p_sys->p_input->stream.pp_areas[i_title] ==
692 p_intf->p_sys->p_input->stream.p_selected_area )
694 p_item_active = p_title_item;
697 /* setup signal hanling */
698 gtk_signal_connect( GTK_OBJECT( p_title_item ),
700 GTK_SIGNAL_FUNC( pf_toggle ),
701 (gpointer)(p_intf->p_sys->p_input->stream.pp_areas[i_title]) );
703 if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
705 /* be sure that menu is sensitive */
706 gtk_widget_set_sensitive( p_navigation, TRUE );
712 p_title_item = gtk_menu_item_new_with_label( psz_name );
715 p_chapter_menu = gtk_menu_new();
716 gtk_object_set_data( GTK_OBJECT( p_chapter_menu ),
719 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb;
721 for( i_chapter = 0 ; i_chapter < i_chapter_nb ; i_chapter++ )
723 /* we group chapters in packets of ten for small screens */
724 if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) )
728 gtk_menu_item_set_submenu(
729 GTK_MENU_ITEM( p_chapter_menu_item ),
731 gtk_menu_append( GTK_MENU( p_chapter_menu ),
732 p_chapter_menu_item );
735 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
736 "%d - %d", i_chapter + 1, i_chapter + 10 );
737 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
738 p_chapter_menu_item =
739 gtk_menu_item_new_with_label( psz_name );
740 gtk_widget_show( p_chapter_menu_item );
741 p_chapter_submenu = gtk_menu_new();
742 gtk_object_set_data( GTK_OBJECT( p_chapter_submenu ),
746 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
747 _("Chapter %d"), i_chapter + 1 );
748 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
750 p_item = gtk_radio_menu_item_new_with_label(
751 p_chapter_group, psz_name );
752 p_chapter_group = gtk_radio_menu_item_group(
753 GTK_RADIO_MENU_ITEM( p_item ) );
754 gtk_widget_show( p_item );
756 #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]
758 p_intf->p_sys->p_input->stream.p_selected_area ) &&
759 ( p_area->i_part == i_chapter + 1 ) )
761 p_item_active = p_item;
765 /* setup signal hanling */
766 gtk_signal_connect( GTK_OBJECT( p_item ),
768 GTK_SIGNAL_FUNC( pf_toggle ),
769 (gpointer)POS2DATA( i_title, i_chapter + 1) );
771 if( i_chapter_nb > 20 )
773 gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item );
777 gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
781 if( i_chapter_nb > 20 )
783 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ),
785 gtk_menu_append( GTK_MENU( p_chapter_menu ),
786 p_chapter_menu_item );
789 /* link the new menu to the title menu item */
790 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
793 if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb > 1 )
795 /* be sure that menu is sensitive */
796 gtk_widget_set_sensitive( p_navigation, TRUE );
799 GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"),
800 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb,
802 p_intf->p_sys->p_input->stream.p_selected_area->i_part +
803 p_intf->p_sys->p_input->stream.p_selected_area->i_id *100,
808 gtk_widget_show( p_title_item );
810 if( i_title_nb > 20 )
812 gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item );
816 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
820 if( i_title_nb > 20 )
822 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
824 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
827 /* be sure that menu is sensitive */
828 gtk_widget_set_sensitive( p_title_menu, TRUE );
830 /* link the new menu to the menubar item */
831 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
833 /* Default selected chapter
834 * We have to release the lock since input_ToggleES needs it */
835 if( p_item_active != NULL )
837 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
841 if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
843 /* be sure that menu is sensitive */
844 gtk_widget_set_sensitive( p_navigation, TRUE );
851 /*****************************************************************************
852 * GtkSetupMenus: function that generates title/chapter/audio/subpic
853 * menus with help from preceding functions
854 *****************************************************************************
855 * Function called with the lock on stream
856 *****************************************************************************/
857 gint GtkSetupMenus( intf_thread_t * p_intf )
859 es_descriptor_t * p_audio_es;
860 es_descriptor_t * p_spu_es;
861 GtkWidget * p_menubar_menu;
862 GtkWidget * p_popup_menu;
865 p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
866 p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |
867 p_intf->p_sys->b_program_update;
868 p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
869 p_intf->p_sys->b_program_update;
871 if( p_intf->p_sys->b_program_update )
873 pgrm_descriptor_t * p_pgrm;
875 if( p_intf->p_sys->p_input->stream.p_new_program )
877 p_pgrm = p_intf->p_sys->p_input->stream.p_new_program;
881 p_pgrm = p_intf->p_sys->p_input->stream.p_selected_program;
884 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
885 p_intf->p_sys->p_window ), "menubar_program" ) );
886 GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm,
887 GtkMenubarProgramToggle );
889 p_intf->p_sys->b_program_update = 1;
890 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
891 p_intf->p_sys->p_popup ), "popup_program" ) );
892 GtkProgramMenu( p_intf, p_popup_menu, p_pgrm,
893 GtkPopupProgramToggle );
895 p_intf->p_sys->b_program_update = 0;
898 if( p_intf->p_sys->b_title_update )
902 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
903 p_intf->p_sys->p_window ), "menubar_title" ) );
904 GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"),
905 p_intf->p_sys->p_input->stream.i_area_nb - 1,
906 p_intf->p_sys->p_input->stream.p_selected_area->i_id,
907 GtkMenubarTitleToggle );
909 snprintf( psz_title, 4, "%d",
910 p_intf->p_sys->p_input->stream.p_selected_area->i_id );
911 psz_title[ 4 ] = '\0';
912 gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
914 p_intf->p_sys->b_title_update = 0;
917 if( p_intf->p_sys->b_chapter_update )
921 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
922 p_intf->p_sys->p_popup ), "popup_navigation" ) );
923 GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
925 GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"),
926 p_intf->p_sys->p_input->stream.i_area_nb - 1,
927 p_intf->p_sys->p_input->stream.p_selected_area->i_id,
928 on_menubar_chapter_toggle );
931 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
932 p_intf->p_sys->p_window ), "menubar_chapter" ) );
934 GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"),
935 p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb,
936 p_intf->p_sys->p_input->stream.p_selected_area->i_part,
937 GtkMenubarChapterToggle );
940 snprintf( psz_chapter, 4, "%d",
941 p_intf->p_sys->p_input->stream.p_selected_area->i_part );
942 psz_chapter[ 4 ] = '\0';
943 gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
945 p_intf->p_sys->i_part =
946 p_intf->p_sys->p_input->stream.p_selected_area->i_part;
948 p_intf->p_sys->b_chapter_update = 0;
951 /* look for selected ES */
955 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ )
957 if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
959 p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
962 if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
964 p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
968 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
971 if( p_intf->p_sys->b_audio_update )
973 /* find audio root menu */
974 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
975 p_intf->p_sys->p_window ), "menubar_audio" ) );
977 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
978 p_intf->p_sys->p_popup ), "popup_audio" ) );
980 p_intf->p_sys->b_audio_update = 1;
981 GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
982 GtkMenubarAudioToggle );
983 p_intf->p_sys->b_audio_update = 1;
984 GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
985 GtkPopupAudioToggle );
987 p_intf->p_sys->b_audio_update = 0;
990 /* sub picture menus */
991 if( p_intf->p_sys->b_spu_update )
993 /* find spu root menu */
994 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
995 p_intf->p_sys->p_window ), "menubar_subpictures" ) );
997 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
998 p_intf->p_sys->p_popup ), "popup_subpictures" ) );
1000 p_intf->p_sys->b_spu_update = 1;
1001 GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
1002 GtkMenubarSubtitleToggle );
1003 p_intf->p_sys->b_spu_update = 1;
1004 GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
1005 GtkPopupSubtitleToggle );
1007 p_intf->p_sys->b_spu_update = 0;
1010 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );