]> git.sesse.net Git - vlc/blobdiff - modules/gui/gtk/menu.c
* gtk: fixed a segfault with deinterlace.
[vlc] / modules / gui / gtk / menu.c
index 510a72492def49f90ca6577d2fb2cbc0787a2ca4..946bc5f03a0260ff3bd1f9053b1f32b8ff418bef 100644 (file)
@@ -2,11 +2,12 @@
  * menu.c : functions to handle menu items.
  *****************************************************************************
  * Copyright (C) 2000, 2001 VideoLAN
- * $Id: menu.c,v 1.2 2002/12/06 16:34:07 sam Exp $
+ * $Id: menu.c,v 1.5 2003/01/22 00:32:32 fenrir Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *          Stéphane Borel <stef@via.ecp.fr>
  *          Johan Bilien <jobi@via.ecp.fr>
+ *          Laurent Aimar <fenrir@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,6 +32,8 @@
 
 #include <vlc/vlc.h>
 #include <vlc/intf.h>
+#include <vlc/aout.h>
+#include <vlc/vout.h>
 
 #ifdef MODULE_NAME_IS_gnome
 #   include <gnome.h>
@@ -63,6 +66,12 @@ static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *,
                           char *, int, int, int,
                    void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) );
 
+static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data );
+static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data );
+static gint GtkDeinterlaceMenus( gpointer          p_data,
+                                 GtkWidget *       p_root,
+                                 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) );
+
 gint GtkSetupMenus( intf_thread_t * p_intf );
 
 /****************************************************************************
@@ -95,7 +104,7 @@ gint GtkSetupMenus( intf_thread_t * p_intf );
             GtkLanguageMenus( p_intf, p_menu, p_es, type, callback );   \
         }                                                               \
                                                                         \
-        p_intf->p_sys->b_update = 0;                                    \
+        p_intf->p_sys->b_update = VLC_FALSE;                            \
     }
 
 /*
@@ -147,22 +156,31 @@ void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
     {
         input_area_t   *p_area;
 
-        gint i_title   = DATA2TITLE( user_data );
-        gint i_chapter = DATA2CHAPTER( user_data );
+        guint i_title   = DATA2TITLE( user_data );
+        guint i_chapter = DATA2CHAPTER( user_data );
 
+        vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
         p_area = p_intf->p_sys->p_input->stream.p_selected_area;
 
+        i_title = __MIN( i_title,
+                         p_intf->p_sys->p_input->stream.i_area_nb - 1 );
+        i_title = __MAX( i_title, 1 );
+
         if( p_area != p_intf->p_sys->p_input->stream.pp_areas[i_title] )
         {
             p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];
-            p_intf->p_sys->b_title_update = 1;
+            p_intf->p_sys->b_title_update = VLC_TRUE;
         }
 
+        i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );
+        i_chapter = __MAX( i_chapter, 1 );
         p_area->i_part = i_chapter;
 
+        vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
+
         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
 
-        p_intf->p_sys->b_chapter_update = 1;
+        p_intf->p_sys->b_chapter_update = VLC_TRUE;
         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
         GtkSetupMenus( p_intf );
         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
@@ -179,17 +197,17 @@ void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem,
                                                                             \
     if( menuitem->active && !p_intf->p_sys->b_program_update )              \
     {                                                                       \
-        u16 i_program_id = (ptrdiff_t)user_data;                            \
+        int i_program_id = (ptrdiff_t)user_data;                            \
                                                                             \
         input_ChangeProgram( p_intf->p_sys->p_input, i_program_id );        \
                                                                             \
-        p_intf->p_sys->b_program_update = 1;                                \
+        p_intf->p_sys->b_program_update = VLC_TRUE;                         \
                                                                             \
         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );      \
         GtkSetupMenus( p_intf );                                            \
         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );    \
                                                                             \
-        p_intf->p_sys->b_program_update = 0;                                \
+        p_intf->p_sys->b_program_update = VLC_FALSE;                        \
                                                                             \
         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );       \
     }
@@ -214,18 +232,24 @@ void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
 
     if( menuitem->active && !p_intf->p_sys->b_title_update )
     {
-        gint i_title = (gint)((long)user_data);
+        guint i_title = (ptrdiff_t)user_data;
+
+        vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
+        i_title = __MIN( i_title,
+                         p_intf->p_sys->p_input->stream.i_area_nb - 1 );
+        i_title = __MAX( i_title, 1 );
+        vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
+
         input_ChangeArea( p_intf->p_sys->p_input,
                           p_intf->p_sys->p_input->stream.pp_areas[i_title] );
 
-        p_intf->p_sys->b_title_update = 1;
+        p_intf->p_sys->b_title_update = VLC_TRUE;
         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
         GtkSetupMenus( p_intf );
         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
-        p_intf->p_sys->b_title_update = 0;
+        p_intf->p_sys->b_title_update = VLC_FALSE;
 
         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
-
     }
 }
 
@@ -237,19 +261,24 @@ void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
 {
     intf_thread_t * p_intf;
     input_area_t *  p_area;
-    gint            i_chapter;
+    guint           i_chapter;
     GtkWidget *     p_popup_menu;
 
     p_intf    = GtkGetIntf( menuitem );
     p_area    = p_intf->p_sys->p_input->stream.p_selected_area;
-    i_chapter = (gint)((long)user_data);
+    i_chapter = (ptrdiff_t)user_data;
 
     if( menuitem->active && !p_intf->p_sys->b_chapter_update )
     {
+        vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
+        i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );
+        i_chapter = __MAX( i_chapter, 1 );
         p_area->i_part = i_chapter;
+        vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
+
         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
 
-        p_intf->p_sys->b_chapter_update = 1;
+        p_intf->p_sys->b_chapter_update = VLC_TRUE;
         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
 
@@ -257,13 +286,162 @@ void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
 
-        p_intf->p_sys->b_chapter_update = 0;
+        p_intf->p_sys->b_chapter_update = VLC_FALSE;
 
         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
     }
 }
 
 
+static void GtkPopupObjectToggle( GtkCheckMenuItem * menuitem, gpointer user_data,
+                                  int i_object_type, char *psz_variable )
+{
+    intf_thread_t   *p_intf = GtkGetIntf( menuitem );
+    GtkLabel        *p_label;
+
+    p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
+
+    if( menuitem->active && !p_intf->p_sys->b_aout_update && !p_intf->p_sys->b_vout_update )
+    {
+        vlc_object_t * p_obj;
+
+        p_obj = (vlc_object_t *)vlc_object_find( p_intf, i_object_type,
+                                                  FIND_ANYWHERE );
+        if( p_obj )
+        {
+            vlc_value_t val;
+
+            gtk_label_get( p_label, &val.psz_string );
+
+            if( var_Set( p_obj, psz_variable, val ) < 0 )
+            {
+                msg_Warn( p_obj, "cannot set variable (%s)", val.psz_string );
+            }
+            vlc_object_release( p_obj );
+        }
+    }
+}
+static void GtkPopupAoutChannelsToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
+{
+    GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_AOUT, "audio-channels" );
+}
+
+static void GtkPopupAoutDeviceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
+{
+    GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_AOUT, "audio-device" );
+}
+
+
+static void GtkPopupVoutDeviceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
+{
+    GtkPopupObjectToggle( menuitem, user_data, VLC_OBJECT_VOUT, "video-device" );
+}
+
+
+static void GtkDeinterlaceUpdate( intf_thread_t *p_intf, char *psz_mode )
+{
+    char *psz_filter;
+    int  i;
+
+    psz_filter = config_GetPsz( p_intf, "filter" );
+
+    if( !strcmp( psz_mode, "None" ) )
+    {
+        config_PutPsz( p_intf, "filter", "" );
+    }
+    else
+    {
+        if( !psz_filter || !*psz_filter )
+        {
+            config_PutPsz( p_intf, "filter", "deinterlace" );
+        }
+        else
+        {
+            if( strstr( psz_filter, "deinterlace" ) == NULL )
+            {
+                psz_filter = realloc( psz_filter, strlen( psz_filter ) + 20 );
+                strcat( psz_filter, ",deinterlace" );
+            }
+            config_PutPsz( p_intf, "filter", psz_filter );
+        }
+
+        config_PutPsz( p_intf, "deinterlace-mode", psz_mode );
+    }
+
+    if( psz_filter )
+        free( psz_filter );
+
+    /* now restart all video stream */
+    if( p_intf->p_sys->p_input )
+    {
+        vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
+#define ES p_intf->p_sys->p_input->stream.pp_es[i]
+        /* create a set of language buttons and append them to the container */
+        for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
+        {
+            if( ( ES->i_cat == VIDEO_ES ) &&
+                    ES->p_decoder_fifo != NULL )
+            {
+                input_UnselectES( p_intf->p_sys->p_input, ES );
+                input_SelectES( p_intf->p_sys->p_input, ES );
+            }
+#undef ES
+        }
+        vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
+    }
+}
+
+static void GtkMenubarDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
+{
+    intf_thread_t   *p_intf = GtkGetIntf( menuitem );
+    GtkLabel        *p_label;
+    char            *psz_mode;
+    GtkWidget       *p_popup_menu;
+
+    p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
+
+    if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
+    {
+        gtk_label_get( p_label, &psz_mode );
+        GtkDeinterlaceUpdate( p_intf, psz_mode );
+
+        p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
+
+        p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                                     p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
+
+        GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
+
+        p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
+
+    }
+}
+
+static void GtkPopupDeinterlaceToggle( GtkCheckMenuItem * menuitem, gpointer user_data )
+{
+    intf_thread_t   *p_intf = GtkGetIntf( menuitem );
+    GtkLabel        *p_label;
+    char            *psz_mode;
+    GtkWidget       *p_menubar_menu;
+
+    p_label = GTK_LABEL( ( GTK_BIN( menuitem )->child ) );
+
+    if( !p_intf->p_sys->b_deinterlace_update && menuitem->active )
+    {
+        gtk_label_get( p_label, &psz_mode );
+        GtkDeinterlaceUpdate( p_intf, psz_mode );
+
+        p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
+
+        p_menubar_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                                     p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
+
+        GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
+
+        p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
+    }
+}
+
 /****************************************************************************
  * Functions to generate menus
  ****************************************************************************/
@@ -310,7 +488,7 @@ static gint GtkRadioMenu( intf_thread_t * p_intf,
     for( i_item = i_start ; i_item <= i_end ; i_item++ )
     {
         /* we group chapters in packets of ten for small screens */
-        if( ( i_item % 10 == i_start ) && ( i_end > 20 ) )
+        if( ( i_item % 10 == i_start ) && ( i_end > i_start + 20 ) )
         {
             if( i_item != i_start )
             {
@@ -348,7 +526,7 @@ static gint GtkRadioMenu( intf_thread_t * p_intf,
                             GTK_SIGNAL_FUNC( pf_toggle ),
                             (gpointer)((long)(i_item)) );
 
-        if( i_end > 20 )
+        if( i_end > i_start + 20 )
         {
             gtk_menu_append( GTK_MENU( p_submenu ), p_item );
         }
@@ -358,7 +536,7 @@ static gint GtkRadioMenu( intf_thread_t * p_intf,
         }
     }
 
-    if( i_end > 20 )
+    if( i_end > i_start + 20 )
     {
         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu );
         gtk_menu_append( GTK_MENU( p_menu ), p_item_group );
@@ -651,17 +829,17 @@ static gint GtkTitleMenu( gpointer       p_data,
     p_chapter_submenu = NULL;
     p_chapter_menu_item = NULL;
     p_item_active = NULL;
-    i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb;
+    i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb - 1;
 
     gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf );
 
     /* loop on titles */
-    for( i_title = 0 ; i_title < i_title_nb ; i_title++ )
+    for( i_title = 1 ; i_title <= i_title_nb ; i_title++ )
     {
         /* we group titles in packets of ten for small screens */
-        if( ( i_title % 10 == 0 ) && ( i_title_nb > 20 ) )
+        if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )
         {
-            if( i_title != 0 )
+            if( i_title != 1 )
             {
                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ),
                                            p_title_submenu );
@@ -679,7 +857,7 @@ static gint GtkTitleMenu( gpointer       p_data,
         }
 
         snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title,
-                  p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb );
+                  p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1);
         psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
 #if 0
         if( pf_toggle == on_menubar_title_toggle )
@@ -717,14 +895,14 @@ static gint GtkTitleMenu( gpointer       p_data,
             gtk_object_set_data( GTK_OBJECT( p_chapter_menu ),
                                  "p_intf", p_intf );
             i_chapter_nb =
-                    p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb;
+               p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1;
 
-            for( i_chapter = 0 ; i_chapter < i_chapter_nb ; i_chapter++ )
+            for( i_chapter = 1 ; i_chapter <= i_chapter_nb ; i_chapter++ )
             {
                 /* we group chapters in packets of ten for small screens */
-                if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) )
+                if( ( i_chapter % 10 == 1 ) && ( i_chapter_nb > 20 ) )
                 {
-                    if( i_chapter != 0 )
+                    if( i_chapter != 1 )
                     {
                         gtk_menu_item_set_submenu(
                                     GTK_MENU_ITEM( p_chapter_menu_item ),
@@ -734,7 +912,7 @@ static gint GtkTitleMenu( gpointer       p_data,
                     }
 
                     snprintf( psz_name, GTK_MENU_LABEL_SIZE,
-                              "%d - %d", i_chapter + 1, i_chapter + 10 );
+                              "%d - %d", i_chapter, i_chapter + 9 );
                     psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
                     p_chapter_menu_item =
                             gtk_menu_item_new_with_label( psz_name );
@@ -745,7 +923,7 @@ static gint GtkTitleMenu( gpointer       p_data,
                 }
 
                 snprintf( psz_name, GTK_MENU_LABEL_SIZE,
-                          _("Chapter %d"), i_chapter + 1 );
+                          _("Chapter %d"), i_chapter );
                 psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0';
 
                 p_item = gtk_radio_menu_item_new_with_label(
@@ -757,7 +935,7 @@ static gint GtkTitleMenu( gpointer       p_data,
 #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]
                 if( ( p_area ==
                         p_intf->p_sys->p_input->stream.p_selected_area ) &&
-                    ( p_area->i_part == i_chapter + 1 ) )
+                    ( p_area->i_part == i_chapter ) )
                 {
                     p_item_active = p_item;
                 }
@@ -767,7 +945,7 @@ static gint GtkTitleMenu( gpointer       p_data,
                 gtk_signal_connect( GTK_OBJECT( p_item ),
                            "toggled",
                            GTK_SIGNAL_FUNC( pf_toggle ),
-                           (gpointer)POS2DATA( i_title, i_chapter + 1) );
+                           (gpointer)POS2DATA( i_title, i_chapter ) );
 
                 if( i_chapter_nb > 20 )
                 {
@@ -798,7 +976,7 @@ static gint GtkTitleMenu( gpointer       p_data,
             }
 #else
             GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"),
-                p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb,
+                p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1,
                 1, i_title * 100,
                 p_intf->p_sys->p_input->stream.p_selected_area->i_part +
                 p_intf->p_sys->p_input->stream.p_selected_area->i_id *100,
@@ -849,6 +1027,211 @@ static gint GtkTitleMenu( gpointer       p_data,
     return TRUE;
 }
 
+/*****************************************************************************
+ * GtkSetupVarMenu :
+ *****************************************************************************
+ *
+ *****************************************************************************/
+static gint GtkSetupVarMenu( intf_thread_t * p_intf,
+                             vlc_object_t * p_object,
+                             GtkWidget *p_root,
+                             char * psz_variable,
+                             void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
+{
+    vlc_value_t         val;
+    char              * psz_value;
+    GtkWidget *         p_menu;
+    GSList *            p_group = NULL;
+    GtkWidget *         p_item;
+    GtkWidget *         p_item_active = NULL;
+
+    int                 i_item;
+
+     /* temporary hack to avoid blank menu when an open menu is removed */
+    if( GTK_MENU_ITEM(p_root)->submenu != NULL )
+    {
+        gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
+    }
+    /* removes previous menu */
+    gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
+    gtk_widget_set_sensitive( p_root, FALSE );
+
+    /* get the current value */
+    if( var_Get( p_object, psz_variable, &val ) < 0 )
+    {
+        return FALSE;
+    }
+    psz_value = val.psz_string;
+
+    if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST, &val ) < 0 )
+    {
+        free( psz_value );
+        return FALSE;
+    }
+
+    /* menu container */
+    p_menu = gtk_menu_new();
+    gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
+
+    for( i_item = 0; i_item < val.p_list->i_count; i_item++ )
+    {
+        p_item = gtk_radio_menu_item_new_with_label( p_group,
+                                                     val.p_list->p_values[i_item].psz_string );
+        p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
+
+        if( !strcmp( psz_value, val.p_list->p_values[i_item].psz_string ) )
+        {
+            p_item_active = p_item;
+        }
+
+        gtk_widget_show( p_item );
+
+        /* signal hanling for off */
+        gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
+                        GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
+
+        gtk_menu_append( GTK_MENU( p_menu ), p_item );
+
+    }
+    /* link the new menu to the menubar item */
+    gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
+
+    if( p_item_active )
+    {
+        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (p_item_active), TRUE);
+    }
+
+    if( val.p_list->i_count > 0 )
+    {
+        gtk_widget_set_sensitive( p_root, TRUE );
+    }
+
+    /* clean up everything */
+    var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val );
+
+    return TRUE;
+}
+
+/*****************************************************************************
+ * GtkDeinterlaceMenus: update interactive menus of the interface
+ *****************************************************************************
+ *****************************************************************************/
+static gint GtkDeinterlaceMenus( gpointer          p_data,
+                                 GtkWidget *       p_root,
+                                 void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
+{
+    intf_thread_t *     p_intf;
+    GtkWidget *         p_menu;
+    GtkWidget *         p_separator;
+    GtkWidget *         p_item;
+    GtkWidget *         p_item_active;
+    GSList *            p_group;
+    guint               i_item;
+    guint               i;
+    char                *ppsz_deinterlace_mode[] = { "discard", "blend", "mean", "bob", "linear", NULL };
+    char                *psz_deinterlace_option;
+    char                *psz_filter;
+
+    p_intf = (intf_thread_t *)p_data;
+
+    /* temporary hack to avoid blank menu when an open menu is removed */
+    if( GTK_MENU_ITEM(p_root)->submenu != NULL )
+    {
+        gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) );
+    }
+    /* removes previous menu */
+    gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
+    gtk_widget_set_sensitive( p_root, FALSE );
+
+    p_group = NULL;
+
+    /* menu container */
+    p_menu = gtk_menu_new();
+    gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf );
+
+    /* special case for "off" item */
+    p_item = gtk_radio_menu_item_new_with_label( p_group, "None" );
+    p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
+
+    gtk_widget_show( p_item );
+
+    /* signal hanling for off */
+    gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
+                        GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
+
+    gtk_menu_append( GTK_MENU( p_menu ), p_item );
+
+    p_separator = gtk_menu_item_new();
+    gtk_widget_set_sensitive( p_separator, FALSE );
+    gtk_widget_show( p_separator );
+    gtk_menu_append( GTK_MENU( p_menu ), p_separator );
+
+
+    /* search actual deinterlace mode */
+    psz_filter = config_GetPsz( p_intf, "filter" );
+    psz_deinterlace_option = strdup( "None" );
+
+    if( psz_filter && *psz_filter )
+    {
+       if( strstr ( psz_filter, "deinterlace" ) )
+       {
+            free( psz_deinterlace_option );
+            psz_deinterlace_option = config_GetPsz( p_intf, "deinterlace-mode" );
+            if( !psz_deinterlace_option )
+                psz_deinterlace_option = strdup( "None" );
+       }
+    }
+    if( psz_filter )
+        free( psz_filter );
+
+    p_item_active = NULL;
+    i_item = 0;
+
+    /* create a set of deinteralce buttons and append them to the container */
+    for( i = 0; ppsz_deinterlace_mode[i] != NULL; i++ )
+    {
+        i_item++;
+
+        p_item = gtk_radio_menu_item_new_with_label( p_group, ppsz_deinterlace_mode[i] );
+        p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
+        gtk_widget_show( p_item );
+
+        if( !strcmp( ppsz_deinterlace_mode[i], psz_deinterlace_option ) )
+        {
+            p_item_active = p_item;
+        }
+        /* setup signal hanling */
+        gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
+                            GTK_SIGNAL_FUNC( pf_toggle ),
+                            NULL );
+
+        gtk_menu_append( GTK_MENU( p_menu ), p_item );
+
+    }
+
+    /* link the new menu to the menubar item */
+    gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
+
+    /* acitvation will call signals so we can only do it
+     * when submenu is attached to menu - to get intf_window
+     * We have to release the lock since input_ToggleES needs it */
+    if( p_item_active != NULL )
+    {
+        gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ),
+                                        TRUE );
+    }
+
+    /* be sure that menu is sensitive if non empty */
+    if( i_item > 0 )
+    {
+        gtk_widget_set_sensitive( p_root, TRUE );
+    }
+
+    return TRUE;
+}
+
+
+
 /*****************************************************************************
  * GtkSetupMenus: function that generates title/chapter/audio/subpic
  * menus with help from preceding functions
@@ -869,6 +1252,21 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
     p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
                                    p_intf->p_sys->b_program_update;
 
+    if( 1 )
+    {
+        p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                                     p_intf->p_sys->p_window ), "menubar_deinterlace" ) );
+        p_popup_menu   = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                                     p_intf->p_sys->p_popup ), "popup_deinterlace" ) );
+
+        p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
+        GtkDeinterlaceMenus( p_intf, p_menubar_menu, GtkMenubarDeinterlaceToggle );
+        p_intf->p_sys->b_deinterlace_update = VLC_TRUE;
+        GtkDeinterlaceMenus( p_intf, p_popup_menu, GtkPopupDeinterlaceToggle );
+
+        p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
+    }
+
     if( p_intf->p_sys->b_program_update )
     {
         pgrm_descriptor_t * p_pgrm;
@@ -887,13 +1285,13 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
         GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm,
                         GtkMenubarProgramToggle );
 
-        p_intf->p_sys->b_program_update = 1;
+        p_intf->p_sys->b_program_update = VLC_TRUE;
         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
                             p_intf->p_sys->p_popup ), "popup_program" ) );
         GtkProgramMenu( p_intf, p_popup_menu, p_pgrm,
                         GtkPopupProgramToggle );
 
-        p_intf->p_sys->b_program_update = 0;
+        p_intf->p_sys->b_program_update = VLC_FALSE;
     }
 
     if( p_intf->p_sys->b_title_update )
@@ -902,7 +1300,7 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
 
         p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
                             p_intf->p_sys->p_window ), "menubar_title" ) );
-        GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 0,
+        GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
                       p_intf->p_sys->p_input->stream.i_area_nb - 1,
                       p_intf->p_sys->p_input->stream.p_selected_area->i_id,
                       GtkMenubarTitleToggle );
@@ -912,7 +1310,7 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
         psz_title[ 4 ] = '\0';
         gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title );
 
-        p_intf->p_sys->b_title_update = 0;
+        p_intf->p_sys->b_title_update = VLC_FALSE;
     }
 
     if( p_intf->p_sys->b_chapter_update )
@@ -923,7 +1321,7 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
                              p_intf->p_sys->p_popup ), "popup_navigation" ) );
         GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle );
 #if 0
-        GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 0,
+        GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 1,
                         p_intf->p_sys->p_input->stream.i_area_nb - 1,
                         p_intf->p_sys->p_input->stream.p_selected_area->i_id,
                         on_menubar_chapter_toggle );
@@ -933,7 +1331,7 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
                              p_intf->p_sys->p_window ), "menubar_chapter" ) );
 
         GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"), 1,
-                        p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb,
+                        p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb - 1,
                         p_intf->p_sys->p_input->stream.p_selected_area->i_part,
                         GtkMenubarChapterToggle );
 
@@ -946,7 +1344,7 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
         p_intf->p_sys->i_part =
                 p_intf->p_sys->p_input->stream.p_selected_area->i_part;
 
-        p_intf->p_sys->b_chapter_update = 0;
+        p_intf->p_sys->b_chapter_update = VLC_FALSE;
     }
 
     /* look for selected ES */
@@ -978,14 +1376,14 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
                      p_intf->p_sys->p_popup ), "popup_audio" ) );
 
-        p_intf->p_sys->b_audio_update = 1;
+        p_intf->p_sys->b_audio_update = VLC_TRUE;
         GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES,
                             GtkMenubarAudioToggle );
-        p_intf->p_sys->b_audio_update = 1;
+        p_intf->p_sys->b_audio_update = VLC_TRUE;
         GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES,
                             GtkPopupAudioToggle );
 
-        p_intf->p_sys->b_audio_update = 0;
+        p_intf->p_sys->b_audio_update = VLC_FALSE;
     }
 
     /* sub picture menus */
@@ -998,16 +1396,82 @@ gint GtkSetupMenus( intf_thread_t * p_intf )
         p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
                      p_intf->p_sys->p_popup ), "popup_subpictures" ) );
 
-        p_intf->p_sys->b_spu_update = 1;
+        p_intf->p_sys->b_spu_update = VLC_TRUE;
         GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES,
                             GtkMenubarSubtitleToggle  );
-        p_intf->p_sys->b_spu_update = 1;
+        p_intf->p_sys->b_spu_update = VLC_TRUE;
         GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES,
                             GtkPopupSubtitleToggle );
 
-        p_intf->p_sys->b_spu_update = 0;
+        p_intf->p_sys->b_spu_update = VLC_FALSE;
     }
+    /* create audio channels and device menu (in menubar _and_ popup */
+    if( p_intf->p_sys->b_aout_update )
+    {
+        aout_instance_t *p_aout;
+
+        p_aout = (aout_instance_t*)vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
+
+        if( p_aout != NULL )
+        {
+            vlc_value_t val;
+            val.b_bool = VLC_FALSE;
+
+            var_Set( (vlc_object_t *)p_aout, "intf-change", val );
+
+            /* audio-channels */
+            p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                              p_intf->p_sys->p_window ), "menubar_audio_channels" ) );
+            p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                         p_intf->p_sys->p_popup ), "popup_audio_channels" ) );
+            GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
+                              "audio-channels",  GtkPopupAoutChannelsToggle );
+            GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
+                              "audio-channels",  GtkPopupAoutChannelsToggle );
+
+            /* audio-device */
+            p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                              p_intf->p_sys->p_window ), "menubar_audio_device" ) );
+            p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                         p_intf->p_sys->p_popup ), "popup_audio_device" ) );
+            GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_popup_menu,
+                              "audio-device",  GtkPopupAoutDeviceToggle );
+            GtkSetupVarMenu( p_intf, (vlc_object_t *)p_aout, p_menubar_menu,
+                              "audio-device",  GtkPopupAoutDeviceToggle );
+
+            vlc_object_release( (vlc_object_t *)p_aout );
+        }
+        p_intf->p_sys->b_aout_update = VLC_FALSE;
+    }
+
+    if( p_intf->p_sys->b_vout_update )
+    {
+        vout_thread_t *p_vout;
 
+        p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
+
+        if( p_vout != NULL )
+        {
+            vlc_value_t val;
+            val.b_bool = VLC_FALSE;
+
+            var_Set( (vlc_object_t *)p_vout, "intf-change", val );
+
+            /* video-device */
+            p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                              p_intf->p_sys->p_window ), "menubar_video_device" ) );
+            p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
+                         p_intf->p_sys->p_popup ), "popup_video_device" ) );
+            GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_popup_menu,
+                              "video-device",  GtkPopupVoutDeviceToggle );
+            GtkSetupVarMenu( p_intf, (vlc_object_t *)p_vout, p_menubar_menu,
+                              "video-device",  GtkPopupVoutDeviceToggle );
+
+
+            vlc_object_release( (vlc_object_t *)p_vout );
+        }
+        p_intf->p_sys->b_vout_update = VLC_FALSE;
+    }
     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
 
     return TRUE;