menu.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:56k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * menu.c : functions to handle menu items.
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2001 VideoLAN
  5.  * $Id: menu.c 7951 2004-06-07 22:11:57Z fenrir $
  6.  *
  7.  * Authors: Sam Hocevar <sam@zoy.org>
  8.  *          St閜hane Borel <stef@via.ecp.fr>
  9.  *          Johan Bilien <jobi@via.ecp.fr>
  10.  *          Laurent Aimar <fenrir@via.ecp.fr>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <sys/types.h>                                              /* off_t */
  30. #include <stdlib.h>
  31. #include <vlc/vlc.h>
  32. #include <vlc/input.h>
  33. #include <vlc/intf.h>
  34. #include <vlc/aout.h>
  35. #include <vlc/vout.h>
  36. #ifdef MODULE_NAME_IS_gnome
  37. #   include <gnome.h>
  38. #else
  39. #   include <gtk/gtk.h>
  40. #endif
  41. #include <string.h>
  42. #include "gtk_callbacks.h"
  43. #include "gtk_interface.h"
  44. #include "gtk_support.h"
  45. #include "playlist.h"
  46. #include "common.h"
  47. /*
  48.  * Local Prototypes
  49.  */
  50. static gint GtkLanguageMenus( gpointer , GtkWidget *, es_descriptor_t *, gint,
  51.                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
  52. void GtkMenubarAudioToggle   ( GtkCheckMenuItem *, gpointer );
  53. void GtkPopupAudioToggle     ( GtkCheckMenuItem *, gpointer );
  54. void GtkMenubarSubtitleToggle( GtkCheckMenuItem *, gpointer );
  55. void GtkPopupSubtitleToggle  ( GtkCheckMenuItem *, gpointer );
  56. static gint GtkTitleMenu( gpointer, GtkWidget *,
  57.                     void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
  58. static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *,
  59.                           char *, int, int, int,
  60.                    void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) );
  61. static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data );
  62. static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data );
  63. static gint GtkDeinterlaceMenus( gpointer          p_data,
  64.                                  GtkWidget *       p_root,
  65.                                  void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
  66. 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.  ****************************************************************************/
  73. #define GTKLANGTOGGLE( window, menu, type, var_name, callback, b_update )
  74.     intf_thread_t *         p_intf;                                     
  75.     GtkWidget *             p_menu;                                     
  76.     es_descriptor_t *       p_es;                                       
  77.                                                                         
  78.     p_intf = GtkGetIntf( menuitem );                                    
  79.                                                                         
  80.     if( !p_intf->p_sys->b_update )                                      
  81.     {                                                                   
  82.         p_menu = GTK_WIDGET( gtk_object_get_data(                       
  83.                    GTK_OBJECT( p_intf->p_sys->window ), (menu) ) );     
  84.         p_es = (es_descriptor_t*)user_data;                             
  85.         if( p_es && menuitem->active )                                  
  86.             var_SetInteger( p_intf->p_sys->p_input, var_name, p_es->i_id ); 
  87.         else                                                            
  88.             var_SetInteger( p_intf->p_sys->p_input, var_name, -1 );     
  89.                                                                         
  90.         p_intf->p_sys->b_update = menuitem->active;                     
  91.                                                                         
  92.         if( p_intf->p_sys->b_update )                                   
  93.         {                                                               
  94.             GtkLanguageMenus( p_intf, p_menu, p_es, type, callback );   
  95.         }                                                               
  96.                                                                         
  97.         p_intf->p_sys->b_update = VLC_FALSE;                            
  98.     }
  99. /*
  100.  * Audio
  101.  */
  102. void GtkMenubarAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  103. {
  104.     GTKLANGTOGGLE( p_popup, "popup_language", AUDIO_ES, "audio-es",
  105.                    GtkPopupAudioToggle, b_audio_update );
  106. }
  107. void GtkPopupAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  108. {
  109.     GTKLANGTOGGLE( p_window, "menubar_audio", AUDIO_ES, "audio-es",
  110.                    GtkMenubarAudioToggle, b_audio_update );
  111. }
  112. /*
  113.  * Subtitles
  114.  */
  115. void GtkMenubarSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  116. {
  117.     GTKLANGTOGGLE( p_popup, "popup_subpictures", SPU_ES, "spu-es",
  118.                    GtkPopupSubtitleToggle, b_spu_update );
  119. }
  120. void GtkPopupSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  121. {
  122.     GTKLANGTOGGLE( p_window, "menubar_subpictures", SPU_ES, "spu-es",
  123.                    GtkMenubarSubtitleToggle, b_spu_update );
  124. }
  125. #undef GTKLANGTOGGLE
  126. /*
  127.  * Navigation
  128.  */
  129. void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
  130.                                gpointer user_data )
  131. {
  132.     intf_thread_t * p_intf = GtkGetIntf( menuitem );
  133.     if( menuitem->active &&
  134.         !p_intf->p_sys->b_title_update &&
  135.         !p_intf->p_sys->b_chapter_update )
  136.     {
  137.         input_area_t   *p_area;
  138.         guint i_title   = DATA2TITLE( user_data );
  139.         guint i_chapter = DATA2CHAPTER( user_data );
  140.         /* FIXME use "navigation" variable */
  141.         var_SetInteger( p_intf->p_sys->p_input, "title", i_title );
  142.         var_SetInteger( p_intf->p_sys->p_input, "chapter", i_chapter );
  143.         p_intf->p_sys->b_title_update = VLC_TRUE;
  144.         p_intf->p_sys->b_chapter_update = VLC_TRUE;
  145.         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
  146.         GtkSetupMenus( p_intf );
  147.         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
  148.     }
  149. }
  150. /*
  151.  * Program
  152.  */
  153. #define GTKPROGRAMTOGGLE( )                                                 
  154.     intf_thread_t * p_intf = GtkGetIntf( menuitem );                        
  155.                                                                             
  156.     if( menuitem->active && !p_intf->p_sys->b_program_update )              
  157.     {                                                                       
  158.         int i_program_id = (ptrdiff_t)user_data;                            
  159.                                                                             
  160.         var_SetInteger( p_intf->p_sys->p_input, "program", i_program_id );  
  161.                                                                             
  162.         p_intf->p_sys->b_program_update = VLC_TRUE;                         
  163.                                                                             
  164.         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );      
  165.         GtkSetupMenus( p_intf );                                            
  166.         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );    
  167.                                                                             
  168.         p_intf->p_sys->b_program_update = VLC_FALSE;                        
  169.                                                                             
  170.         var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );       
  171.     }
  172. void GtkMenubarProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  173. {
  174.     GTKPROGRAMTOGGLE( );
  175. }
  176. void GtkPopupProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  177. {
  178.     GTKPROGRAMTOGGLE( );
  179. }
  180. /*
  181.  * Title
  182.  */
  183. void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  184. {
  185.     intf_thread_t * p_intf = GtkGetIntf( menuitem );
  186.     if( menuitem->active && !p_intf->p_sys->b_title_update )
  187.     {
  188.         guint i_title = (ptrdiff_t)user_data;
  189.         var_SetInteger( p_intf->p_sys->p_input, "title", i_title );
  190.         p_intf->p_sys->b_title_update = VLC_TRUE;
  191.         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
  192.         GtkSetupMenus( p_intf );
  193.         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
  194.     }
  195. }
  196. /*
  197.  * Chapter
  198.  */
  199. void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  200. {
  201.     intf_thread_t * p_intf;
  202.     input_area_t *  p_area;
  203.     guint           i_chapter;
  204.     GtkWidget *     p_popup_menu;
  205.     p_intf    = GtkGetIntf( menuitem );
  206.     p_area    = p_intf->p_sys->p_input->stream.p_selected_area;
  207.     i_chapter = (ptrdiff_t)user_data;
  208.     if( menuitem->active && !p_intf->p_sys->b_chapter_update )
  209.     {
  210.         var_SetInteger( p_intf->p_sys->p_input, "chapter", i_chapter );
  211.         p_intf->p_sys->b_chapter_update = VLC_TRUE;
  212.         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  213.                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
  214.         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
  215.         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
  216.         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
  217.         p_intf->p_sys->b_chapter_update = VLC_FALSE;
  218.     }
  219. }
  220. static void GtkPopupObjectToggle( GtkCheckMenuItem * menuitem,
  221.     gpointer user_data, int i_object_type, char *psz_variable )
  222. {
  223.     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
  224.     GtkLabel        *p_label;
  225.     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
  226.     if( menuitem->active && !p_intf->p_sys->b_aout_update &&
  227.         !p_intf->p_sys->b_vout_update )
  228.     {
  229.         vlc_object_t * p_obj;
  230.         p_obj = (vlc_object_t *)vlc_object_find( p_intf, i_object_type,
  231.                                                   FIND_ANYWHERE );
  232.         if( p_obj )
  233.         {
  234.             vlc_value_t val;
  235.             if( user_data )
  236.             {
  237.                 val = (vlc_value_t)user_data;
  238.             }
  239.             else
  240.             {
  241.                 gtk_label_get( p_label, &val.psz_string );
  242.             }
  243.             if( var_Set( p_obj, psz_variable, val ) < 0 )
  244.             {
  245.                 msg_Warn( p_obj, "cannot set variable (%s)", val.psz_string );
  246.             }
  247.             vlc_object_release( p_obj );
  248.         }
  249.     }
  250. }
  251. static void GtkPopupAoutChannelsToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  252. {
  253.     GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_AOUT, "audio-channels" );
  254. }
  255. static void GtkPopupAoutDeviceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  256. {
  257.     GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_AOUT, "audio-device" );
  258. }
  259. static void GtkPopupVoutDeviceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  260. {
  261.     GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_VOUT, "video-device" );
  262. }
  263. static void GtkDeinterlaceUpdate( intf_thread_t *p_intf, char *psz_mode )
  264. {
  265.     char *psz_filter;
  266.     unsigned int  i;
  267.     psz_filter = config_GetPsz( p_intf, "filter" );
  268.     if( !strcmp( psz_mode, "None" ) )
  269.     {
  270.         config_PutPsz( p_intf, "filter", "" );
  271.     }
  272.     else
  273.     {
  274.         if( !psz_filter || !*psz_filter )
  275.         {
  276.             config_PutPsz( p_intf, "filter", "deinterlace" );
  277.         }
  278.         else
  279.         {
  280.             if( strstr( psz_filter, "deinterlace" ) == NULL )
  281.             {
  282.                 psz_filter = realloc( psz_filter, strlen( psz_filter ) + 20 );
  283.                 strcat( psz_filter, ",deinterlace" );
  284.             }
  285.             config_PutPsz( p_intf, "filter", psz_filter );
  286.         }
  287.     }
  288.     if( psz_filter )
  289.         free( psz_filter );
  290.     /* now restart all video stream */
  291.     if( p_intf->p_sys->p_input )
  292.     {
  293.         vout_thread_t *p_vout;
  294.         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
  295.         /* Warn the vout we are about to change the filter chain */
  296.         p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
  297.                                   FIND_ANYWHERE );
  298.         if( p_vout )
  299.         {
  300.             p_vout->b_filter_change = VLC_TRUE;
  301.             vlc_object_release( p_vout );
  302.         }
  303. #define ES p_intf->p_sys->p_input->stream.pp_es[i]
  304.         /* create a set of language buttons and append them to the container */
  305.         for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
  306.         {
  307.             if( ( ES->i_cat == VIDEO_ES ) &&
  308.                     ES->p_dec != NULL )
  309.             {
  310.                 input_UnselectES( p_intf->p_sys->p_input, ES );
  311.                 input_SelectES( p_intf->p_sys->p_input, ES );
  312.             }
  313. #undef ES
  314.         }
  315.         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
  316.     }
  317.     if( strcmp( psz_mode, "None" ) )
  318.     {
  319.         vout_thread_t *p_vout;
  320.         p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
  321.                                   FIND_ANYWHERE );
  322.         if( p_vout )
  323.         {
  324.             vlc_value_t val;
  325.             val.psz_string = psz_mode;
  326.             if( var_Set( p_vout, "deinterlace-mode", val ) != VLC_SUCCESS )
  327.                 config_PutPsz( p_intf, "deinterlace-mode", psz_mode );
  328.             vlc_object_release( p_vout );
  329.         }
  330.         else
  331.             config_PutPsz( p_intf, "deinterlace-mode", psz_mode );
  332.     }
  333. }
  334. static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  335. {
  336.     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
  337.     GtkLabel        *p_label;
  338.     char            *psz_mode;
  339.     GtkWidget       *p_popup_menu;
  340.     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
  341.     if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
  342.     {
  343.         gtk_label_get( p_label, &psz_mode );
  344.         GtkDeinterlaceUpdate( p_intf, psz_mode );
  345.         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
  346.         p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  347.                                      p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
  348.         GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
  349.         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
  350.     }
  351. }
  352. static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
  353. {
  354.     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
  355.     GtkLabel        *p_label;
  356.     char            *psz_mode;
  357.     GtkWidget       *p_menubar_menu;
  358.     p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
  359.     if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
  360.     {
  361.         gtk_label_get( p_label, &psz_mode );
  362.         GtkDeinterlaceUpdate( p_intf, psz_mode );
  363.         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
  364.         p_menubar_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  365.                                      p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
  366.         GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
  367.         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
  368.     }
  369. }
  370. /****************************************************************************
  371.  * Functions to generate menus
  372.  ****************************************************************************/
  373. /*****************************************************************************
  374.  * GtkRadioMenu: update interactive menus of the interface
  375.  *****************************************************************************
  376.  * Sets up menus with information from input
  377.  * Warning: since this function is designed to be called by management
  378.  * function, the interface lock has to be taken
  379.  *****************************************************************************/
  380. static gint GtkRadioMenu( intf_thread_t * p_intf,
  381.                             GtkWidget * p_root, GSList * p_menu_group,
  382.                             char * psz_item_name,
  383.                             int i_start, int i_end, int i_selected,
  384.                      void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) )
  385. {
  386.     char                psz_name[ GTK_MENU_LABEL_SIZE ];
  387.     GtkWidget *         p_menu;
  388.     GtkWidget *         p_submenu;
  389.     GtkWidget *         p_item_group;
  390.     GtkWidget *         p_item;
  391.     GtkWidget *         p_item_selected;
  392.     GSList *            p_group;
  393.     gint                i_item;
  394.     /* temporary hack to avoid blank menu when an open menu is removed */
  395.     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
  396.     {
  397.         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
  398.     }
  399.     /* removes previous menu */
  400.     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
  401.     gtk_widget_set_sensitive( p_root, FALSE );
  402.     p_item_group = NULL;
  403.     p_submenu = NULL;
  404.     p_item_selected = NULL;
  405.     p_group = p_menu_group;
  406.     p_menu = gtk_menu_new();
  407.     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
  408.     for( i_item = i_start ; i_item <= i_end ; i_item++ )
  409.     {
  410.         /* we group chapters in packets of ten for small screens */
  411.         if( ( i_item % 10 == i_start ) && ( i_end > i_start + 20 ) )
  412.         {
  413.             if( i_item != i_start )
  414.             {
  415.                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ),
  416.                                            p_submenu );
  417.                 gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
  418.             }
  419.             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
  420.                       "%ss %d to %d", psz_item_name, i_item, i_item + 9 );
  421.             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  422.             p_item_group = gtk_menu_item_new_with_label( psz_name );
  423.             gtk_widget_show( p_item_group );
  424.             p_submenu = gtk_menu_new();
  425.             gtk_object_set_data( GTK_OBJECT( p_submenu ), "p_intf", p_intf );
  426.         }
  427.         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d",
  428.                   psz_item_name, i_item );
  429.         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  430.         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
  431.         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  432.         if( i_selected == i_item )
  433.         {
  434.             p_item_selected = p_item;
  435.         }
  436.         gtk_widget_show( p_item );
  437.         /* setup signal hanling */
  438.         gtk_signal_connect( GTK_OBJECT( p_item ),
  439.                             "toggled",
  440.                             GTK_SIGNAL_FUNC( pf_toggle ),
  441.                             (gpointer)((long)(i_item)) );
  442.         if( i_end > i_start + 20 )
  443.         {
  444.             gtk_menu_append( GTK_MENU( p_submenu ), p_item );
  445.         }
  446.         else
  447.         {
  448.             gtk_menu_append( GTK_MENU( p_menu ), p_item );
  449.         }
  450.     }
  451.     if( i_end > i_start + 20 )
  452.     {
  453.         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
  454.         gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
  455.     }
  456.     /* link the new menu to the title menu item */
  457.     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
  458.     /* toggle currently selected chapter
  459.      * We have to release the lock since input_ToggleES needs it */
  460.     if( p_item_selected != NULL )
  461.     {
  462.         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ),
  463.                                         TRUE );
  464.     }
  465.     /* be sure that menu is sensitive, if there are several items */
  466.     if( i_end > i_start )
  467.     {
  468.         gtk_widget_set_sensitive( p_root, TRUE );
  469.     }
  470.     return TRUE;
  471. }
  472. /*****************************************************************************
  473.  * GtkProgramMenu: update the programs menu of the interface
  474.  *****************************************************************************
  475.  * Builds the program menu according to what have been found in the PAT
  476.  * by the input. Usefull for multi-programs streams such as DVB ones.
  477.  *****************************************************************************/
  478. static gint GtkProgramMenu( gpointer            p_data,
  479.                             GtkWidget *         p_root,
  480.                             pgrm_descriptor_t * p_pgrm,
  481.                       void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
  482. {
  483.     intf_thread_t *     p_intf;
  484.     GtkWidget *         p_menu;
  485.     GtkWidget *         p_item;
  486.     GtkWidget *         p_item_active;
  487.     GSList *            p_group;
  488.     char                psz_name[ GTK_MENU_LABEL_SIZE ];
  489.     guint               i;
  490.     /* cast */
  491.     p_intf = (intf_thread_t *)p_data;
  492.     /* temporary hack to avoid blank menu when an open menu is removed */
  493.     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
  494.     {
  495.         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
  496.     }
  497.     /* removes previous menu */
  498.     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
  499.     gtk_widget_set_sensitive( p_root, FALSE );
  500.     p_group = NULL;
  501.     /* menu container */
  502.     p_menu = gtk_menu_new();
  503.     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
  504.     p_item_active = NULL;
  505.     /* create a set of program buttons and append them to the container */
  506.     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_pgrm_number ; i++ )
  507.     {
  508.         snprintf( psz_name, GTK_MENU_LABEL_SIZE, "id %d",
  509.             p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );
  510.         psz_name[GTK_MENU_LABEL_SIZE-1] = '';
  511.         p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
  512.         p_group =
  513.             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  514.         if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )
  515.         {
  516.             /* don't lose p_item when we append into menu */
  517.             p_item_active = p_item;
  518.         }
  519.         gtk_widget_show( p_item );
  520.         /* setup signal hanling */
  521.         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  522.                         GTK_SIGNAL_FUNC( pf_toggle ),
  523.                         (gpointer)(ptrdiff_t)( p_intf->p_sys->p_input->
  524.                         stream.pp_programs[i]->i_number ) );
  525.         gtk_menu_append( GTK_MENU( p_menu ), p_item );
  526.     }
  527.     /* link the new menu to the menubar item */
  528.     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
  529.     /* activation will call signals so we can only do it
  530.      * when submenu is attached to menu - to get intf_window
  531.      * We have to release the lock since input_ToggleES needs it */
  532.     if( p_item_active != NULL )
  533.     {
  534.         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
  535.                                         TRUE );
  536.     }
  537.     /* be sure that menu is sensitive if more than 1 program */
  538.     if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )
  539.     {
  540.         gtk_widget_set_sensitive( p_root, TRUE );
  541.     }
  542.     return TRUE;
  543. }
  544. /*****************************************************************************
  545.  * GtkLanguageMenus: update interactive menus of the interface
  546.  *****************************************************************************
  547.  * Sets up menus with information from input:
  548.  *  -languages
  549.  *  -sub-pictures
  550.  * Warning: since this function is designed to be called by management
  551.  * function, the interface lock has to be taken
  552.  *****************************************************************************/
  553. static gint GtkLanguageMenus( gpointer          p_data,
  554.                               GtkWidget *       p_root,
  555.                               es_descriptor_t * p_es,
  556.                               gint              i_cat,
  557.                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
  558. {
  559.     intf_thread_t *     p_intf;
  560.     GtkWidget *         p_menu;
  561.     GtkWidget *         p_separator;
  562.     GtkWidget *         p_item;
  563.     GtkWidget *         p_item_active;
  564.     GSList *            p_group;
  565.     char                psz_name[ GTK_MENU_LABEL_SIZE ];
  566.     guint               i_item;
  567.     guint               i;
  568.     p_intf = (intf_thread_t *)p_data;
  569.     /* temporary hack to avoid blank menu when an open menu is removed */
  570.     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
  571.     {
  572.         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
  573.     }
  574.     /* removes previous menu */
  575.     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
  576.     gtk_widget_set_sensitive( p_root, FALSE );
  577.     p_group = NULL;
  578.     /* menu container */
  579.     p_menu = gtk_menu_new();
  580.     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
  581.     /* special case for "off" item */
  582.     snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("None") );
  583.     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  584.     p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
  585.     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  586.     gtk_widget_show( p_item );
  587.     /* signal hanling for off */
  588.     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  589.                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
  590.     gtk_menu_append( GTK_MENU( p_menu ), p_item );
  591.     p_separator = gtk_menu_item_new();
  592.     gtk_widget_set_sensitive( p_separator, FALSE );
  593.     gtk_widget_show( p_separator );
  594.     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
  595.     p_item_active = NULL;
  596.     i_item = 0;
  597.     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
  598. #define ES p_intf->p_sys->p_input->stream.pp_es[i]
  599.     /* create a set of language buttons and append them to the container */
  600.     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
  601.     {
  602.         if( ( ES->i_cat == i_cat ) &&
  603.             ( !ES->p_pgrm ||
  604.               ES->p_pgrm ==
  605.                  p_intf->p_sys->p_input->stream.p_selected_program ) )
  606.         {
  607.             i_item++;
  608.             if( !p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc ||
  609.                 !*p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc )
  610.             {
  611.                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
  612.                           "Language %d", i_item );
  613.                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  614.             }
  615.             else
  616.             {
  617.                 strcpy( psz_name,
  618.                         p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc );
  619.             }
  620.             p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
  621.             p_group =
  622.                 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  623.             if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )
  624.             {
  625.                 /* don't lose p_item when we append into menu */
  626.                 p_item_active = p_item;
  627.             }
  628.             gtk_widget_show( p_item );
  629.             /* setup signal hanling */
  630.             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  631.                             GTK_SIGNAL_FUNC( pf_toggle ),
  632.                             (gpointer)( p_intf->p_sys->p_input->stream.pp_es[i] ) );
  633.             gtk_menu_append( GTK_MENU( p_menu ), p_item );
  634.         }
  635.     }
  636.     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
  637.     /* link the new menu to the menubar item */
  638.     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
  639.     /* acitvation will call signals so we can only do it
  640.      * when submenu is attached to menu - to get intf_window
  641.      * We have to release the lock since input_ToggleES needs it */
  642.     if( p_item_active != NULL )
  643.     {
  644.         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
  645.                                         TRUE );
  646.     }
  647.     /* be sure that menu is sensitive if non empty */
  648.     if( i_item > 0 )
  649.     {
  650.         gtk_widget_set_sensitive( p_root, TRUE );
  651.     }
  652.     return TRUE;
  653. }
  654. /*****************************************************************************
  655.  * GtkTitleMenu: sets menus for titles and chapters selection
  656.  *****************************************************************************
  657.  * Generates two types of menus:
  658.  *  -simple list of titles
  659.  *  -cascaded lists of chapters for each title
  660.  *****************************************************************************/
  661. static gint GtkTitleMenu( gpointer       p_data,
  662.                           GtkWidget *    p_navigation,
  663.                           void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
  664. {
  665.     intf_thread_t *     p_intf;
  666.     char                psz_name[ GTK_MENU_LABEL_SIZE ];
  667.     GtkWidget *         p_title_menu;
  668.     GtkWidget *         p_title_submenu;
  669.     GtkWidget *         p_title_item;
  670.     GtkWidget *         p_item_active;
  671.     GtkWidget *         p_chapter_menu;
  672.     GtkWidget *         p_chapter_submenu;
  673.     GtkWidget *         p_title_menu_item;
  674.     GtkWidget *         p_chapter_menu_item;
  675.     GtkWidget *         p_item;
  676.     GSList *            p_title_group;
  677.     GSList *            p_chapter_group;
  678.     guint               i_title;
  679.     guint               i_chapter;
  680.     guint               i_title_nb;
  681.     guint               i_chapter_nb;
  682.     /* cast */
  683.     p_intf = (intf_thread_t*)p_data;
  684.     /* temporary hack to avoid blank menu when an open menu is removed */
  685.     if( GTK_MENU_ITEM(p_navigation)->submenu != NULL )
  686.     {
  687.         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) );
  688.     }
  689.     /* removes previous menu */
  690.     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) );
  691.     gtk_widget_set_sensitive( p_navigation, FALSE );
  692.     p_title_menu = gtk_menu_new();
  693.     p_title_group = NULL;
  694.     p_title_submenu = NULL;
  695.     p_title_menu_item = NULL;
  696.     p_chapter_group = NULL;
  697.     p_chapter_submenu = NULL;
  698.     p_chapter_menu_item = NULL;
  699.     p_item_active = NULL;
  700.     i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb - 1;
  701.     gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf );
  702.     /* loop on titles */
  703.     for( i_title = 1 ; i_title <= i_title_nb ; i_title++ )
  704.     {
  705.         /* we group titles in packets of ten for small screens */
  706.         if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )
  707.         {
  708.             if( i_title != 1 )
  709.             {
  710.                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
  711.                                            p_title_submenu );
  712.                 gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
  713.             }
  714.             snprintf( psz_name, GTK_MENU_LABEL_SIZE,
  715.                       "%d - %d", i_title, i_title + 9 );
  716.             psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  717.             p_title_menu_item = gtk_menu_item_new_with_label( psz_name );
  718.             gtk_widget_show( p_title_menu_item );
  719.             p_title_submenu = gtk_menu_new();
  720.             gtk_object_set_data( GTK_OBJECT( p_title_submenu ),
  721.                                  "p_intf", p_intf );
  722.         }
  723.         snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title,
  724.                   p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1);
  725.         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  726. #if 0
  727.         if( pf_toggle == on_menubar_title_toggle )
  728.         {
  729.             p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
  730.                                                            psz_name );
  731.             p_title_group =
  732.               gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
  733.             if( p_intf->p_sys->p_input->stream.pp_areas[i_title] ==
  734.                          p_intf->p_sys->p_input->stream.p_selected_area )
  735.             {
  736.                 p_item_active = p_title_item;
  737.             }
  738.             /* setup signal hanling */
  739.             gtk_signal_connect( GTK_OBJECT( p_title_item ),
  740.                      "toggled",
  741.                      GTK_SIGNAL_FUNC( pf_toggle ),
  742.                      (gpointer)(p_intf->p_sys->p_input->stream.pp_areas[i_title]) );
  743.             if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
  744.             {
  745.                 /* be sure that menu is sensitive */
  746.                 gtk_widget_set_sensitive( p_navigation, TRUE );
  747.             }
  748.         }
  749.         else
  750. #endif
  751.         {
  752.             p_title_item = gtk_menu_item_new_with_label( psz_name );
  753. #if 1
  754.             p_chapter_menu = gtk_menu_new();
  755.             gtk_object_set_data( GTK_OBJECT( p_chapter_menu ),
  756.                                  "p_intf", p_intf );
  757.             i_chapter_nb =
  758.                p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1;
  759.             for( i_chapter = 1 ; i_chapter <= i_chapter_nb ; i_chapter++ )
  760.             {
  761.                 /* we group chapters in packets of ten for small screens */
  762.                 if( ( i_chapter % 10 == 1 ) && ( i_chapter_nb > 20 ) )
  763.                 {
  764.                     if( i_chapter != 1 )
  765.                     {
  766.                         gtk_menu_item_set_submenu(
  767.                                     GTK_MENU_ITEM( p_chapter_menu_item ),
  768.                                     p_chapter_submenu );
  769.                         gtk_menu_append( GTK_MENU( p_chapter_menu ),
  770.                                          p_chapter_menu_item );
  771.                     }
  772.                     snprintf( psz_name, GTK_MENU_LABEL_SIZE,
  773.                               "%d - %d", i_chapter, i_chapter + 9 );
  774.                     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  775.                     p_chapter_menu_item =
  776.                             gtk_menu_item_new_with_label( psz_name );
  777.                     gtk_widget_show( p_chapter_menu_item );
  778.                     p_chapter_submenu = gtk_menu_new();
  779.                     gtk_object_set_data( GTK_OBJECT( p_chapter_submenu ),
  780.                                          "p_intf", p_intf );
  781.                 }
  782.                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
  783.                           _("Chapter %d"), i_chapter );
  784.                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '';
  785.                 p_item = gtk_radio_menu_item_new_with_label(
  786.                                                 p_chapter_group, psz_name );
  787.                 p_chapter_group = gtk_radio_menu_item_group(
  788.                                                 GTK_RADIO_MENU_ITEM( p_item ) );
  789.                 gtk_widget_show( p_item );
  790. #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]
  791.                 if( ( p_area ==
  792.                         p_intf->p_sys->p_input->stream.p_selected_area ) &&
  793.                     ( p_area->i_part == i_chapter ) )
  794.                 {
  795.                     p_item_active = p_item;
  796.                 }
  797. #undef p_area
  798.                 /* setup signal hanling */
  799.                 gtk_signal_connect( GTK_OBJECT( p_item ),
  800.                            "toggled",
  801.                            GTK_SIGNAL_FUNC( pf_toggle ),
  802.                            (gpointer)POS2DATA( i_title, i_chapter ) );
  803.                 if( i_chapter_nb > 20 )
  804.                 {
  805.                     gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item );
  806.                 }
  807.                 else
  808.                 {
  809.                     gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
  810.                 }
  811.             }
  812.             if( i_chapter_nb > 20 )
  813.             {
  814.                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ),
  815.                                            p_chapter_submenu );
  816.                 gtk_menu_append( GTK_MENU( p_chapter_menu ),
  817.                                  p_chapter_menu_item );
  818.             }
  819.             /* link the new menu to the title menu item */
  820.             gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
  821.                                        p_chapter_menu );
  822.             if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb > 1 )
  823.             {
  824.                 /* be sure that menu is sensitive */
  825.                 gtk_widget_set_sensitive( p_navigation, TRUE );
  826.             }
  827. #else
  828.             GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"),
  829.                 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1,
  830.                 1, i_title * 100,
  831.                 p_intf->p_sys->p_input->stream.p_selected_area->i_part +
  832.                 p_intf->p_sys->p_input->stream.p_selected_area->i_id *100,
  833.                 pf_toggle );
  834. #endif
  835.         }
  836.         gtk_widget_show( p_title_item );
  837.         if( i_title_nb > 20 )
  838.         {
  839.             gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item );
  840.         }
  841.         else
  842.         {
  843.             gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
  844.         }
  845.     }
  846.     if( i_title_nb > 20 )
  847.     {
  848.         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
  849.                                    p_title_submenu );
  850.         gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item );
  851.     }
  852.     /* be sure that menu is sensitive */
  853.     gtk_widget_set_sensitive( p_title_menu, TRUE );
  854.     /* link the new menu to the menubar item */
  855.     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
  856.     /* Default selected chapter
  857.      * We have to release the lock since input_ToggleES needs it */
  858.     if( p_item_active != NULL )
  859.     {
  860.         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
  861.                                         TRUE );
  862.     }
  863. #if 0
  864.     if( p_intf->p_sys->p_input->stream.i_area_nb > 1 )
  865.     {
  866.         /* be sure that menu is sensitive */
  867.         gtk_widget_set_sensitive( p_navigation, TRUE );
  868.     }
  869. #endif
  870.     return TRUE;
  871. }
  872. /*****************************************************************************
  873.  * GtkSetupVarMenu :
  874.  *****************************************************************************
  875.  *
  876.  *****************************************************************************/
  877. static gint GtkSetupVarMenu( intf_thread_t * p_intf,
  878.                              vlc_object_t * p_object,
  879.                              GtkWidget *p_root,
  880.                              char * psz_variable,
  881.                              void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
  882. {
  883.     vlc_value_t         val, text, val_list, text_list;
  884.     GtkWidget *         p_menu;
  885.     GSList *            p_group = NULL;
  886.     GtkWidget *         p_item;
  887.     GtkWidget *         p_item_active = NULL;
  888.     int                 i_item, i_type;
  889.      /* temporary hack to avoid blank menu when an open menu is removed */
  890.     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
  891.     {
  892.         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
  893.     }
  894.     /* removes previous menu */
  895.     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
  896.     gtk_widget_set_sensitive( p_root, FALSE );
  897.     /* Check the type of the object variable */
  898.     i_type = var_Type( p_object, psz_variable );
  899.     /* Make sure we want to display the variable */
  900.     if( i_type & VLC_VAR_HASCHOICE )
  901.     {
  902.         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
  903.         if( val.i_int == 0 ) return FALSE;
  904.     }
  905.     /* Get the descriptive name of the variable */
  906.     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
  907.     /* get the current value */
  908.     if( var_Get( p_object, psz_variable, &val ) < 0 )
  909.     {
  910.         return FALSE;
  911.     }
  912.     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
  913.                     &val_list, &text_list ) < 0 )
  914.     {
  915.         if( i_type == VLC_VAR_STRING ) free( val.psz_string );
  916.         return FALSE;
  917.     }
  918.     /* menu container */
  919.     p_menu = gtk_menu_new();
  920.     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
  921.     for( i_item = 0; i_item < val_list.p_list->i_count; i_item++ )
  922.     {
  923.         switch( i_type & VLC_VAR_TYPE )
  924.         {
  925.         case VLC_VAR_STRING:
  926.             p_item = gtk_radio_menu_item_new_with_label( p_group,
  927.                      text_list.p_list->p_values[i_item].psz_string ?
  928.                      text_list.p_list->p_values[i_item].psz_string :
  929.                      val_list.p_list->p_values[i_item].psz_string );
  930.             /* signal hanling for off */
  931.             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  932.                 GTK_SIGNAL_FUNC ( pf_toggle ),
  933.                 /* FIXME memory leak */
  934.                 strdup(val_list.p_list->p_values[i_item].psz_string) );
  935.             if( !strcmp( val.psz_string,
  936.                          val_list.p_list->p_values[i_item].psz_string ) )
  937.             {
  938.                 p_item_active = p_item;
  939.             }
  940.             break;
  941.         case VLC_VAR_INTEGER:
  942.             p_item = gtk_radio_menu_item_new_with_label( p_group,
  943.                      text_list.p_list->p_values[i_item].psz_string ?
  944.                      text_list.p_list->p_values[i_item].psz_string :
  945.                      NULL /* FIXME */ );
  946.             /* signal hanling for off */
  947.             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  948.                 GTK_SIGNAL_FUNC ( pf_toggle ),
  949.                 (gpointer)val_list.p_list->p_values[i_item].i_int );
  950.             if( val.i_int == val_list.p_list->p_values[i_item].i_int )
  951.             {
  952.                 p_item_active = p_item;
  953.             }
  954.             break;
  955.         default:
  956.             /* FIXME */
  957.             return FALSE;
  958.         }
  959.         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  960.         gtk_widget_show( p_item );
  961.         gtk_menu_append( GTK_MENU( p_menu ), p_item );
  962.     }
  963.     /* link the new menu to the menubar item */
  964.     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
  965.     if( p_item_active )
  966.     {
  967.         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(p_item_active),
  968.                                         TRUE );
  969.     }
  970.     if( val_list.p_list->i_count > 0 )
  971.     {
  972.         gtk_widget_set_sensitive( p_root, TRUE );
  973.     }
  974.     /* clean up everything */
  975.     if( i_type == VLC_VAR_STRING ) free( val.psz_string );
  976.     var_Change( p_object, psz_variable, VLC_VAR_FREELIST,
  977.                 &val_list, &text_list );
  978.     return TRUE;
  979. }
  980. /*****************************************************************************
  981.  * GtkDeinterlaceMenus: update interactive menus of the interface
  982.  *****************************************************************************
  983.  *****************************************************************************/
  984. static gint GtkDeinterlaceMenus( gpointer          p_data,
  985.                                  GtkWidget *       p_root,
  986.                                  void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
  987. {
  988.     intf_thread_t *     p_intf;
  989.     GtkWidget *         p_menu;
  990.     GtkWidget *         p_separator;
  991.     GtkWidget *         p_item;
  992.     GtkWidget *         p_item_active;
  993.     GSList *            p_group;
  994.     guint               i_item;
  995.     guint               i;
  996.     char                *ppsz_deinterlace_mode[] = { "discard", "blend", "mean", "bob", "linear", NULL };
  997.     char                *psz_deinterlace_option;
  998.     char                *psz_filter;
  999.     p_intf = (intf_thread_t *)p_data;
  1000.     /* temporary hack to avoid blank menu when an open menu is removed */
  1001.     if( GTK_MENU_ITEM(p_root)->submenu != NULL )
  1002.     {
  1003.         gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
  1004.     }
  1005.     /* removes previous menu */
  1006.     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
  1007.     gtk_widget_set_sensitive( p_root, FALSE );
  1008.     p_group = NULL;
  1009.     /* menu container */
  1010.     p_menu = gtk_menu_new();
  1011.     gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
  1012.     /* special case for "off" item */
  1013.     p_item = gtk_radio_menu_item_new_with_label( p_group, "None" );
  1014.     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  1015.     gtk_widget_show( p_item );
  1016.     /* signal hanling for off */
  1017.     gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  1018.                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
  1019.     gtk_menu_append( GTK_MENU( p_menu ), p_item );
  1020.     p_separator = gtk_menu_item_new();
  1021.     gtk_widget_set_sensitive( p_separator, FALSE );
  1022.     gtk_widget_show( p_separator );
  1023.     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
  1024.     /* search actual deinterlace mode */
  1025.     psz_filter = config_GetPsz( p_intf, "filter" );
  1026.     psz_deinterlace_option = strdup( "None" );
  1027.     if( psz_filter && *psz_filter )
  1028.     {
  1029.        if( strstr ( psz_filter, "deinterlace" ) )
  1030.        {
  1031.             vlc_value_t val;
  1032.             vout_thread_t *p_vout;
  1033.             p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
  1034.                                       FIND_ANYWHERE );
  1035.             if( p_vout &&
  1036.                 var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
  1037.             {
  1038.                 if( val.psz_string && *val.psz_string )
  1039.                 {
  1040.                     free( psz_deinterlace_option );
  1041.                     psz_deinterlace_option = val.psz_string;
  1042.                 }
  1043.                 else if( val.psz_string ) free( val.psz_string );
  1044.             }
  1045.             if( p_vout ) vlc_object_release( p_vout );
  1046.        }
  1047.     }
  1048.     if( psz_filter )
  1049.         free( psz_filter );
  1050.     p_item_active = NULL;
  1051.     i_item = 0;
  1052.     /* create a set of deinteralce buttons and append them to the container */
  1053.     for( i = 0; ppsz_deinterlace_mode[i] != NULL; i++ )
  1054.     {
  1055.         i_item++;
  1056.         p_item = gtk_radio_menu_item_new_with_label( p_group, ppsz_deinterlace_mode[i] );
  1057.         p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
  1058.         gtk_widget_show( p_item );
  1059.         if( !strcmp( ppsz_deinterlace_mode[i], psz_deinterlace_option ) )
  1060.         {
  1061.             p_item_active = p_item;
  1062.         }
  1063.         /* setup signal hanling */
  1064.         gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
  1065.                             GTK_SIGNAL_FUNC( pf_toggle ),
  1066.                             NULL );
  1067.         gtk_menu_append( GTK_MENU( p_menu ), p_item );
  1068.     }
  1069.     /* link the new menu to the menubar item */
  1070.     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
  1071.     /* acitvation will call signals so we can only do it
  1072.      * when submenu is attached to menu - to get intf_window
  1073.      * We have to release the lock since input_ToggleES needs it */
  1074.     if( p_item_active != NULL )
  1075.     {
  1076.         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
  1077.                                         TRUE );
  1078.     }
  1079.     /* be sure that menu is sensitive if non empty */
  1080.     if( i_item > 0 )
  1081.     {
  1082.         gtk_widget_set_sensitive( p_root, TRUE );
  1083.     }
  1084.     return TRUE;
  1085. }
  1086. /*****************************************************************************
  1087.  * GtkSetupMenus: function that generates title/chapter/audio/subpic
  1088.  * menus with help from preceding functions
  1089.  *****************************************************************************
  1090.  * Function called with the lock on stream
  1091.  *****************************************************************************/
  1092. gint GtkSetupMenus( intf_thread_t * p_intf )
  1093. {
  1094.     es_descriptor_t *   p_audio_es;
  1095.     es_descriptor_t *   p_spu_es;
  1096.     GtkWidget *         p_menubar_menu;
  1097.     GtkWidget *         p_popup_menu;
  1098.     guint               i;
  1099.     p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
  1100.     p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |
  1101.                                      p_intf->p_sys->b_program_update;
  1102.     p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
  1103.                                    p_intf->p_sys->b_program_update;
  1104.     if( 1 )
  1105.     {
  1106.         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1107.                                      p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
  1108.         p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1109.                                      p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
  1110.         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
  1111.         GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
  1112.         p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
  1113.         GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
  1114.         p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
  1115.     }
  1116.     if( p_intf->p_sys->b_program_update )
  1117.     {
  1118.         pgrm_descriptor_t * p_pgrm;
  1119.         if( p_intf->p_sys->p_input->stream.p_new_program )
  1120.         {
  1121.             p_pgrm = p_intf->p_sys->p_input->stream.p_new_program;
  1122.         }
  1123.         else
  1124.         {
  1125.             p_pgrm = p_intf->p_sys->p_input->stream.p_selected_program;
  1126.         }
  1127.         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1128.                             p_intf->p_sys->p_window ), "menubar_program" ) );
  1129.         GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm,
  1130.                         GtkMenubarProgramToggle );
  1131.         p_intf->p_sys->b_program_update = VLC_TRUE;
  1132.         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1133.                             p_intf->p_sys->p_popup ), "popup_program" ) );
  1134.         GtkProgramMenu( p_intf, p_popup_menu, p_pgrm,
  1135.                         GtkPopupProgramToggle );
  1136.         p_intf->p_sys->b_program_update = VLC_FALSE;
  1137.     }
  1138.     if( p_intf->p_sys->b_title_update )
  1139.     {
  1140.         char            psz_title[5];
  1141.         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1142.                             p_intf->p_sys->p_window ), "menubar_title" ) );
  1143.         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
  1144.                       p_intf->p_sys->p_input->stream.i_area_nb - 1,
  1145.                       p_intf->p_sys->p_input->stream.p_selected_area->i_id,
  1146.                       GtkMenubarTitleToggle );
  1147.         snprintf( psz_title, 4, "%d",
  1148.                   p_intf->p_sys->p_input->stream.p_selected_area->i_id );
  1149.         psz_title[ 4 ] = '';
  1150.         gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
  1151.         p_intf->p_sys->b_title_update = VLC_FALSE;
  1152.     }
  1153.     if( p_intf->p_sys->b_chapter_update )
  1154.     {
  1155.         char            psz_chapter[5];
  1156.         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1157.                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
  1158.         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
  1159. #if 0
  1160.         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
  1161.                         p_intf->p_sys->p_input->stream.i_area_nb - 1,
  1162.                         p_intf->p_sys->p_input->stream.p_selected_area->i_id,
  1163.                         on_menubar_chapter_toggle );
  1164. #endif
  1165.         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1166.                              p_intf->p_sys->p_window ), "menubar_chapter" ) );
  1167.         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"), 1,
  1168.                         p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb - 1,
  1169.                         p_intf->p_sys->p_input->stream.p_selected_area->i_part,
  1170.                         GtkMenubarChapterToggle );
  1171.         snprintf( psz_chapter, 4, "%d",
  1172.                   p_intf->p_sys->p_input->stream.p_selected_area->i_part );
  1173.         psz_chapter[ 4 ] = '';
  1174.         gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter );
  1175.         p_intf->p_sys->i_part =
  1176.                 p_intf->p_sys->p_input->stream.p_selected_area->i_part;
  1177.         p_intf->p_sys->b_chapter_update = VLC_FALSE;
  1178.     }
  1179.     /* look for selected ES */
  1180.     p_audio_es = NULL;
  1181.     p_spu_es = NULL;
  1182.     for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ )
  1183.     {
  1184.         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
  1185.         {
  1186.             p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
  1187.         }
  1188.         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
  1189.         {
  1190.             p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
  1191.         }
  1192.     }
  1193.     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
  1194.     /* audio menus */
  1195.     if( p_intf->p_sys->b_audio_update )
  1196.     {
  1197.         /* find audio root menu */
  1198.         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1199.                              p_intf->p_sys->p_window ), "menubar_audio" ) );
  1200.         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1201.                      p_intf->p_sys->p_popup ), "popup_language" ) );
  1202.         p_intf->p_sys->b_audio_update = VLC_TRUE;
  1203.         GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
  1204.                             GtkMenubarAudioToggle );
  1205.         p_intf->p_sys->b_audio_update = VLC_TRUE;
  1206.         GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
  1207.                             GtkPopupAudioToggle );
  1208.         p_intf->p_sys->b_audio_update = VLC_FALSE;
  1209.     }
  1210.     /* sub picture menus */
  1211.     if( p_intf->p_sys->b_spu_update )
  1212.     {
  1213.         /* find spu root menu */
  1214.         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1215.                           p_intf->p_sys->p_window ), "menubar_subpictures" ) );
  1216.         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1217.                      p_intf->p_sys->p_popup ), "popup_subpictures" ) );
  1218.         p_intf->p_sys->b_spu_update = VLC_TRUE;
  1219.         GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
  1220.                             GtkMenubarSubtitleToggle  );
  1221.         p_intf->p_sys->b_spu_update = VLC_TRUE;
  1222.         GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
  1223.                             GtkPopupSubtitleToggle );
  1224.         p_intf->p_sys->b_spu_update = VLC_FALSE;
  1225.     }
  1226.     /* create audio channels and device menu (in menubar _and_ popup */
  1227.     if( p_intf->p_sys->b_aout_update )
  1228.     {
  1229.         aout_instance_t *p_aout;
  1230.         p_aout = (aout_instance_t*)vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
  1231.         if( p_aout != NULL )
  1232.         {
  1233.             vlc_value_t val;
  1234.             val.b_bool = VLC_FALSE;
  1235.             var_Set( (vlc_object_t *)p_aout, "intf-change", val );
  1236.             /* audio-channels */
  1237.             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1238.                               p_intf->p_sys->p_window ), "menubar_audio_channels" ) );
  1239.             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1240.                          p_intf->p_sys->p_popup ), "popup_audio_channels" ) );
  1241.             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
  1242.                               "audio-channels",  GtkPopupAoutChannelsToggle );
  1243.             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
  1244.                               "audio-channels",  GtkPopupAoutChannelsToggle );
  1245.             /* audio-device */
  1246.             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1247.                               p_intf->p_sys->p_window ), "menubar_audio_device" ) );
  1248.             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1249.                          p_intf->p_sys->p_popup ), "popup_audio_device" ) );
  1250.             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
  1251.                               "audio-device",  GtkPopupAoutDeviceToggle );
  1252.             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
  1253.                               "audio-device",  GtkPopupAoutDeviceToggle );
  1254.             vlc_object_release( (vlc_object_t *)p_aout );
  1255.         }
  1256.         p_intf->p_sys->b_aout_update = VLC_FALSE;
  1257.     }
  1258.     if( p_intf->p_sys->b_vout_update )
  1259.     {
  1260.         vout_thread_t *p_vout;
  1261.         p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
  1262.         if( p_vout != NULL )
  1263.         {
  1264.             vlc_value_t val;
  1265.             val.b_bool = VLC_FALSE;
  1266.             var_Set( (vlc_object_t *)p_vout, "intf-change", val );
  1267.             /* video-device */
  1268.             p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1269.                               p_intf->p_sys->p_window ), "menubar_video_device" ) );
  1270.             p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
  1271.                          p_intf->p_sys->p_popup ), "popup_video_device" ) );
  1272.             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_popup_menu,
  1273.                               "video-device",  GtkPopupVoutDeviceToggle );
  1274.             GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_menubar_menu,
  1275.                               "video-device",  GtkPopupVoutDeviceToggle );
  1276.             vlc_object_release( (vlc_object_t *)p_vout );
  1277.         }
  1278.         p_intf->p_sys->b_vout_update = VLC_FALSE;
  1279.     }
  1280.     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
  1281.     return TRUE;
  1282. }