1 /*****************************************************************************
2 * menu.c : functions to handle menu items.
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: menu.c,v 1.1 2002/08/04 17:23:43 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"
53 static gint GtkLanguageMenus( gpointer , GtkWidget *, es_descriptor_t *, gint,
54 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
56 void GtkMenubarAudioToggle ( GtkCheckMenuItem *, gpointer );
57 void GtkPopupAudioToggle ( GtkCheckMenuItem *, gpointer );
58 void GtkMenubarSubtitleToggle( GtkCheckMenuItem *, gpointer );
59 void GtkPopupSubtitleToggle ( GtkCheckMenuItem *, gpointer );
60 static gint GtkTitleMenu( gpointer, GtkWidget *,
61 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
62 static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *,
63 char *, int, int, int,
64 void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) );
66 gint GtkSetupMenus( intf_thread_t * p_intf );
68 /****************************************************************************
69 * Gtk*Toggle: callbacks to toggle the value of a checkmenuitem
70 ****************************************************************************
71 * We need separate functions for menubar and popup here since we can't use
72 * user_data to transmit intf_* and we need to refresh the other menu.
73 ****************************************************************************/
75 #define GTKLANGTOGGLE( window, menu, type, callback, b_update ) \
76 intf_thread_t * p_intf; \
78 es_descriptor_t * p_es; \
80 p_intf = GtkGetIntf( menuitem ); \
82 if( !p_intf->p_sys->b_update ) \
84 p_menu = GTK_WIDGET( gtk_object_get_data( \
85 GTK_OBJECT( p_intf->p_sys->window ), (menu) ) ); \
86 p_es = (es_descriptor_t*)user_data; \
88 input_ToggleES( p_intf->p_sys->p_input, \
89 p_es, menuitem->active ); \
91 p_intf->p_sys->b_update = menuitem->active; \
93 if( p_intf->p_sys->b_update ) \
95 GtkLanguageMenus( p_intf, p_menu, p_es, type, callback ); \
98 p_intf->p_sys->b_update = 0; \
105 void GtkMenubarAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
107 GTKLANGTOGGLE( p_popup, "popup_audio", AUDIO_ES,
108 GtkPopupAudioToggle, b_audio_update );
111 void GtkPopupAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
113 GTKLANGTOGGLE( p_window, "menubar_audio", AUDIO_ES,
114 GtkMenubarAudioToggle, b_audio_update );
121 void GtkMenubarSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
123 GTKLANGTOGGLE( p_popup, "popup_subpictures", SPU_ES,
124 GtkPopupSubtitleToggle, b_spu_update );
127 void GtkPopupSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
129 GTKLANGTOGGLE( p_window, "menubar_subpictures", SPU_ES,
130 GtkMenubarSubtitleToggle, b_spu_update );
139 void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
142 intf_thread_t * p_intf = GtkGetIntf( menuitem );
144 if( menuitem->active &&
145 !p_intf->p_sys->b_title_update &&
146 !p_intf->p_sys->b_chapter_update )
148 input_area_t *p_area;
150 gint i_title = DATA2TITLE( user_data );
151 gint i_chapter = DATA2CHAPTER( user_data );
153 p_area = p_intf->p_sys->p_input->stream.p_selected_area;
155 if( p_area != p_intf->p_sys->p_input->stream.pp_areas[i_title] )
157 p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];
158 p_intf->p_sys->b_title_update = 1;
161 p_area->i_part = i_chapter;
163 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
165 p_intf->p_sys->b_chapter_update = 1;
166 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
167 GtkSetupMenus( p_intf );
168 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
170 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
177 #define GTKPROGRAMTOGGLE( ) \
178 intf_thread_t * p_intf = GtkGetIntf( menuitem ); \
180 if( menuitem->active && !p_intf->p_sys->b_program_update ) \
182 u16 i_program_id = (ptrdiff_t)user_data; \
184 input_ChangeProgram( p_intf->p_sys->p_input, i_program_id ); \
186 p_intf->p_sys->b_program_update = 1; \
188 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); \
189 GtkSetupMenus( p_intf ); \
190 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); \
192 p_intf->p_sys->b_program_update = 0; \
194 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); \
197 void GtkMenubarProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
202 void GtkPopupProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
211 void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
213 intf_thread_t * p_intf = GtkGetIntf( menuitem );
215 if( menuitem->active && !p_intf->p_sys->b_title_update )
217 gint i_title = (gint)((long)user_data);
218 input_ChangeArea( p_intf->p_sys->p_input,
219 p_intf->p_sys->p_input->stream.pp_areas[i_title] );
221 p_intf->p_sys->b_title_update = 1;
222 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
223 GtkSetupMenus( p_intf );
224 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
225 p_intf->p_sys->b_title_update = 0;
227 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
236 void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
238 intf_thread_t * p_intf;
239 input_area_t * p_area;
241 GtkWidget * p_popup_menu;
243 p_intf = GtkGetIntf( menuitem );
244 p_area = p_intf->p_sys->p_input->stream.p_selected_area;
245 i_chapter = (gint)((long)user_data);
247 if( menuitem->active && !p_intf->p_sys->b_chapter_update )
249 p_area->i_part = i_chapter;
250 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
252 p_intf->p_sys->b_chapter_update = 1;
253 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
254 p_intf->p_sys->p_popup ), "popup_navigation" ) );
256 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
257 GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
258 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
260 p_intf->p_sys->b_chapter_update = 0;
262 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
267 /****************************************************************************
268 * Functions to generate menus
269 ****************************************************************************/
271 /*****************************************************************************
272 * GtkRadioMenu: update interactive menus of the interface
273 *****************************************************************************
274 * Sets up menus with information from input
275 * Warning: since this function is designed to be called by management
276 * function, the interface lock has to be taken
277 *****************************************************************************/
278 static gint GtkRadioMenu( intf_thread_t * p_intf,
279 GtkWidget * p_root, GSList * p_menu_group,
280 char * psz_item_name,
281 int i_start, int i_end, int i_selected,
282 void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) )
284 char psz_name[ GTK_MENU_LABEL_SIZE ];
286 GtkWidget * p_submenu;
287 GtkWidget * p_item_group;
289 GtkWidget * p_item_selected;
293 /* temporary hack to avoid blank menu when an open menu is removed */
294 if( GTK_MENU_ITEM(p_root)->submenu != NULL )
296 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
298 /* removes previous menu */
299 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
300 gtk_widget_set_sensitive( p_root, FALSE );
304 p_item_selected = NULL;
305 p_group = p_menu_group;
307 p_menu = gtk_menu_new();
308 gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
310 for( i_item = i_start ; i_item <= i_end ; i_item++ )
312 /* we group chapters in packets of ten for small screens */
313 if( ( i_item % 10 == i_start ) && ( i_end > 20 ) )
315 if( i_item != i_start )
317 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ),
319 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
322 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
323 "%ss %d to %d", psz_item_name, i_item, i_item + 9 );
324 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
325 p_item_group = gtk_menu_item_new_with_label( psz_name );
326 gtk_widget_show( p_item_group );
327 p_submenu = gtk_menu_new();
328 gtk_object_set_data( GTK_OBJECT( p_submenu ), "p_intf", p_intf );
331 snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d",
332 psz_item_name, i_item );
333 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
335 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
336 p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
338 if( i_selected == i_item )
340 p_item_selected = p_item;
343 gtk_widget_show( p_item );
345 /* setup signal hanling */
346 gtk_signal_connect( GTK_OBJECT( p_item ),
348 GTK_SIGNAL_FUNC( pf_toggle ),
349 (gpointer)((long)(i_item)) );
353 gtk_menu_append( GTK_MENU( p_submenu ), p_item );
357 gtk_menu_append( GTK_MENU( p_menu ), p_item );
363 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
364 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
367 /* link the new menu to the title menu item */
368 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
370 /* toggle currently selected chapter
371 * We have to release the lock since input_ToggleES needs it */
372 if( p_item_selected != NULL )
374 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ),
378 /* be sure that menu is sensitive, if there are several items */
379 if( i_end > i_start )
381 gtk_widget_set_sensitive( p_root, TRUE );
387 /*****************************************************************************
388 * GtkProgramMenu: update the programs menu of the interface
389 *****************************************************************************
390 * Builds the program menu according to what have been found in the PAT
391 * by the input. Usefull for multi-programs streams such as DVB ones.
392 *****************************************************************************/
393 static gint GtkProgramMenu( gpointer p_data,
395 pgrm_descriptor_t * p_pgrm,
396 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
398 intf_thread_t * p_intf;
401 GtkWidget * p_item_active;
403 char psz_name[ GTK_MENU_LABEL_SIZE ];
407 p_intf = (intf_thread_t *)p_data;
409 /* temporary hack to avoid blank menu when an open menu is removed */
410 if( GTK_MENU_ITEM(p_root)->submenu != NULL )
412 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
414 /* removes previous menu */
415 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
416 gtk_widget_set_sensitive( p_root, FALSE );
421 p_menu = gtk_menu_new();
422 gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
424 p_item_active = NULL;
426 /* create a set of program buttons and append them to the container */
427 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_pgrm_number ; i++ )
429 snprintf( psz_name, GTK_MENU_LABEL_SIZE, "id %d",
430 p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );
431 psz_name[GTK_MENU_LABEL_SIZE-1] = '\0';
433 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
435 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
437 if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )
439 /* don't lose p_item when we append into menu */
440 p_item_active = p_item;
443 gtk_widget_show( p_item );
445 /* setup signal hanling */
446 gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
447 GTK_SIGNAL_FUNC( pf_toggle ),
448 (gpointer)(ptrdiff_t)( p_intf->p_sys->p_input->
449 stream.pp_programs[i]->i_number ) );
451 gtk_menu_append( GTK_MENU( p_menu ), p_item );
454 /* link the new menu to the menubar item */
455 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
457 /* activation will call signals so we can only do it
458 * when submenu is attached to menu - to get intf_window
459 * We have to release the lock since input_ToggleES needs it */
460 if( p_item_active != NULL )
462 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
466 /* be sure that menu is sensitive if more than 1 program */
467 if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )
469 gtk_widget_set_sensitive( p_root, TRUE );
475 /*****************************************************************************
476 * GtkLanguageMenus: update interactive menus of the interface
477 *****************************************************************************
478 * Sets up menus with information from input:
481 * Warning: since this function is designed to be called by management
482 * function, the interface lock has to be taken
483 *****************************************************************************/
484 static gint GtkLanguageMenus( gpointer p_data,
486 es_descriptor_t * p_es,
488 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
490 intf_thread_t * p_intf;
492 GtkWidget * p_separator;
494 GtkWidget * p_item_active;
496 char psz_name[ GTK_MENU_LABEL_SIZE ];
500 p_intf = (intf_thread_t *)p_data;
502 /* temporary hack to avoid blank menu when an open menu is removed */
503 if( GTK_MENU_ITEM(p_root)->submenu != NULL )
505 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
507 /* removes previous menu */
508 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
509 gtk_widget_set_sensitive( p_root, FALSE );
514 p_menu = gtk_menu_new();
515 gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
517 /* special case for "off" item */
518 snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("None") );
519 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
521 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
522 p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
524 gtk_widget_show( p_item );
526 /* signal hanling for off */
527 gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
528 GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
530 gtk_menu_append( GTK_MENU( p_menu ), p_item );
532 p_separator = gtk_menu_item_new();
533 gtk_widget_set_sensitive( p_separator, FALSE );
534 gtk_widget_show( p_separator );
535 gtk_menu_append( GTK_MENU( p_menu ), p_separator );
537 p_item_active = NULL;
540 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
542 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
543 /* create a set of language buttons and append them to the container */
544 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
546 if( ( ES->i_cat == i_cat ) &&
549 p_intf->p_sys->p_input->stream.p_selected_program ) )
553 p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc );
554 if( psz_name[0] == '\0' )
556 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
557 "Language %d", i_item );
558 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
561 p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
563 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
565 if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )
567 /* don't lose p_item when we append into menu */
568 p_item_active = p_item;
571 gtk_widget_show( p_item );
573 /* setup signal hanling */
574 gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
575 GTK_SIGNAL_FUNC( pf_toggle ),
576 (gpointer)( p_intf->p_sys->p_input->stream.pp_es[i] ) );
578 gtk_menu_append( GTK_MENU( p_menu ), p_item );
582 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
584 /* link the new menu to the menubar item */
585 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
587 /* acitvation will call signals so we can only do it
588 * when submenu is attached to menu - to get intf_window
589 * We have to release the lock since input_ToggleES needs it */
590 if( p_item_active != NULL )
592 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
596 /* be sure that menu is sensitive if non empty */
599 gtk_widget_set_sensitive( p_root, TRUE );
605 /*****************************************************************************
606 * GtkTitleMenu: sets menus for titles and chapters selection
607 *****************************************************************************
608 * Generates two types of menus:
609 * -simple list of titles
610 * -cascaded lists of chapters for each title
611 *****************************************************************************/
612 static gint GtkTitleMenu( gpointer p_data,
613 GtkWidget * p_navigation,
614 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
616 intf_thread_t * p_intf;
617 char psz_name[ GTK_MENU_LABEL_SIZE ];
618 GtkWidget * p_title_menu;
619 GtkWidget * p_title_submenu;
620 GtkWidget * p_title_item;
621 GtkWidget * p_item_active;
622 GtkWidget * p_chapter_menu;
623 GtkWidget * p_chapter_submenu;
624 GtkWidget * p_title_menu_item;
625 GtkWidget * p_chapter_menu_item;
627 GSList * p_title_group;
628 GSList * p_chapter_group;
635 p_intf = (intf_thread_t*)p_data;
637 /* temporary hack to avoid blank menu when an open menu is removed */
638 if( GTK_MENU_ITEM(p_navigation)->submenu != NULL )
640 gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) );
642 /* removes previous menu */
643 gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) );
644 gtk_widget_set_sensitive( p_navigation, FALSE );
646 p_title_menu = gtk_menu_new();
647 p_title_group = NULL;
648 p_title_submenu = NULL;
649 p_title_menu_item = NULL;
650 p_chapter_group = NULL;
651 p_chapter_submenu = NULL;
652 p_chapter_menu_item = NULL;
653 p_item_active = NULL;
654 i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb;
656 gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf );
659 for( i_title = 0 ; i_title < i_title_nb ; i_title++ )
661 /* we group titles in packets of ten for small screens */
662 if( ( i_title % 10 == 0 ) && ( i_title_nb > 20 ) )
666 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
668 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
671 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
672 "%d - %d", i_title, i_title + 9 );
673 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
674 p_title_menu_item = gtk_menu_item_new_with_label( psz_name );
675 gtk_widget_show( p_title_menu_item );
676 p_title_submenu = gtk_menu_new();
677 gtk_object_set_data( GTK_OBJECT( p_title_submenu ),
681 snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title,
682 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb );
683 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
685 if( pf_toggle == on_menubar_title_toggle )
687 p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
690 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
692 if( p_intf->p_sys->p_input->stream.pp_areas[i_title] ==
693 p_intf->p_sys->p_input->stream.p_selected_area )
695 p_item_active = p_title_item;
698 /* setup signal hanling */
699 gtk_signal_connect( GTK_OBJECT( p_title_item ),
701 GTK_SIGNAL_FUNC( pf_toggle ),
702 (gpointer)(p_intf->p_sys->p_input->stream.pp_areas[i_title]) );
704 if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
706 /* be sure that menu is sensitive */
707 gtk_widget_set_sensitive( p_navigation, TRUE );
713 p_title_item = gtk_menu_item_new_with_label( psz_name );
716 p_chapter_menu = gtk_menu_new();
717 gtk_object_set_data( GTK_OBJECT( p_chapter_menu ),
720 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb;
722 for( i_chapter = 0 ; i_chapter < i_chapter_nb ; i_chapter++ )
724 /* we group chapters in packets of ten for small screens */
725 if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) )
729 gtk_menu_item_set_submenu(
730 GTK_MENU_ITEM( p_chapter_menu_item ),
732 gtk_menu_append( GTK_MENU( p_chapter_menu ),
733 p_chapter_menu_item );
736 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
737 "%d - %d", i_chapter + 1, i_chapter + 10 );
738 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
739 p_chapter_menu_item =
740 gtk_menu_item_new_with_label( psz_name );
741 gtk_widget_show( p_chapter_menu_item );
742 p_chapter_submenu = gtk_menu_new();
743 gtk_object_set_data( GTK_OBJECT( p_chapter_submenu ),
747 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
748 _("Chapter %d"), i_chapter + 1 );
749 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
751 p_item = gtk_radio_menu_item_new_with_label(
752 p_chapter_group, psz_name );
753 p_chapter_group = gtk_radio_menu_item_group(
754 GTK_RADIO_MENU_ITEM( p_item ) );
755 gtk_widget_show( p_item );
757 #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]
759 p_intf->p_sys->p_input->stream.p_selected_area ) &&
760 ( p_area->i_part == i_chapter + 1 ) )
762 p_item_active = p_item;
766 /* setup signal hanling */
767 gtk_signal_connect( GTK_OBJECT( p_item ),
769 GTK_SIGNAL_FUNC( pf_toggle ),
770 (gpointer)POS2DATA( i_title, i_chapter + 1) );
772 if( i_chapter_nb > 20 )
774 gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item );
778 gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
782 if( i_chapter_nb > 20 )
784 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ),
786 gtk_menu_append( GTK_MENU( p_chapter_menu ),
787 p_chapter_menu_item );
790 /* link the new menu to the title menu item */
791 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
794 if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb > 1 )
796 /* be sure that menu is sensitive */
797 gtk_widget_set_sensitive( p_navigation, TRUE );
800 GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"),
801 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb,
803 p_intf->p_sys->p_input->stream.p_selected_area->i_part +
804 p_intf->p_sys->p_input->stream.p_selected_area->i_id *100,
809 gtk_widget_show( p_title_item );
811 if( i_title_nb > 20 )
813 gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item );
817 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
821 if( i_title_nb > 20 )
823 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
825 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
828 /* be sure that menu is sensitive */
829 gtk_widget_set_sensitive( p_title_menu, TRUE );
831 /* link the new menu to the menubar item */
832 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
834 /* Default selected chapter
835 * We have to release the lock since input_ToggleES needs it */
836 if( p_item_active != NULL )
838 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
842 if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
844 /* be sure that menu is sensitive */
845 gtk_widget_set_sensitive( p_navigation, TRUE );
852 /*****************************************************************************
853 * GtkSetupMenus: function that generates title/chapter/audio/subpic
854 * menus with help from preceding functions
855 *****************************************************************************
856 * Function called with the lock on stream
857 *****************************************************************************/
858 gint GtkSetupMenus( intf_thread_t * p_intf )
860 es_descriptor_t * p_audio_es;
861 es_descriptor_t * p_spu_es;
862 GtkWidget * p_menubar_menu;
863 GtkWidget * p_popup_menu;
866 p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
867 p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |
868 p_intf->p_sys->b_program_update;
869 p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
870 p_intf->p_sys->b_program_update;
872 if( p_intf->p_sys->b_program_update )
874 pgrm_descriptor_t * p_pgrm;
876 if( p_intf->p_sys->p_input->stream.p_new_program )
878 p_pgrm = p_intf->p_sys->p_input->stream.p_new_program;
882 p_pgrm = p_intf->p_sys->p_input->stream.p_selected_program;
885 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
886 p_intf->p_sys->p_window ), "menubar_program" ) );
887 GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm,
888 GtkMenubarProgramToggle );
890 p_intf->p_sys->b_program_update = 1;
891 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
892 p_intf->p_sys->p_popup ), "popup_program" ) );
893 GtkProgramMenu( p_intf, p_popup_menu, p_pgrm,
894 GtkPopupProgramToggle );
896 p_intf->p_sys->b_program_update = 0;
899 if( p_intf->p_sys->b_title_update )
903 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
904 p_intf->p_sys->p_window ), "menubar_title" ) );
905 GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 0,
906 p_intf->p_sys->p_input->stream.i_area_nb - 1,
907 p_intf->p_sys->p_input->stream.p_selected_area->i_id,
908 GtkMenubarTitleToggle );
910 snprintf( psz_title, 4, "%d",
911 p_intf->p_sys->p_input->stream.p_selected_area->i_id );
912 psz_title[ 4 ] = '\0';
913 gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
915 p_intf->p_sys->b_title_update = 0;
918 if( p_intf->p_sys->b_chapter_update )
922 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
923 p_intf->p_sys->p_popup ), "popup_navigation" ) );
924 GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
926 GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 0,
927 p_intf->p_sys->p_input->stream.i_area_nb - 1,
928 p_intf->p_sys->p_input->stream.p_selected_area->i_id,
929 on_menubar_chapter_toggle );
932 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
933 p_intf->p_sys->p_window ), "menubar_chapter" ) );
935 GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"), 1,
936 p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb,
937 p_intf->p_sys->p_input->stream.p_selected_area->i_part,
938 GtkMenubarChapterToggle );
941 snprintf( psz_chapter, 4, "%d",
942 p_intf->p_sys->p_input->stream.p_selected_area->i_part );
943 psz_chapter[ 4 ] = '\0';
944 gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
946 p_intf->p_sys->i_part =
947 p_intf->p_sys->p_input->stream.p_selected_area->i_part;
949 p_intf->p_sys->b_chapter_update = 0;
952 /* look for selected ES */
956 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ )
958 if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
960 p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
963 if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
965 p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
969 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
972 if( p_intf->p_sys->b_audio_update )
974 /* find audio root menu */
975 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
976 p_intf->p_sys->p_window ), "menubar_audio" ) );
978 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
979 p_intf->p_sys->p_popup ), "popup_audio" ) );
981 p_intf->p_sys->b_audio_update = 1;
982 GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
983 GtkMenubarAudioToggle );
984 p_intf->p_sys->b_audio_update = 1;
985 GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
986 GtkPopupAudioToggle );
988 p_intf->p_sys->b_audio_update = 0;
991 /* sub picture menus */
992 if( p_intf->p_sys->b_spu_update )
994 /* find spu root menu */
995 p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
996 p_intf->p_sys->p_window ), "menubar_subpictures" ) );
998 p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
999 p_intf->p_sys->p_popup ), "popup_subpictures" ) );
1001 p_intf->p_sys->b_spu_update = 1;
1002 GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
1003 GtkMenubarSubtitleToggle );
1004 p_intf->p_sys->b_spu_update = 1;
1005 GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
1006 GtkPopupSubtitleToggle );
1008 p_intf->p_sys->b_spu_update = 0;
1011 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );