]> git.sesse.net Git - vlc/blob - plugins/gnome/intf_gnome.c
9021e0635efeada030ba8cb20da033f0dcb8a463
[vlc] / plugins / gnome / intf_gnome.c
1 /*****************************************************************************
2  * intf_gnome.c: Gnome interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  * $Id: intf_gnome.c,v 1.21 2001/03/15 00:37:04 stef Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #define MODULE_NAME gnome
25 #include "modules_inner.h"
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include "defs.h"
31
32 #include <errno.h>                                                 /* ENOMEM */
33 #include <stdlib.h>                                                /* free() */
34 #include <string.h>                                            /* strerror() */
35 #include <stdio.h>
36
37 #include <gnome.h>
38
39 #include "config.h"
40 #include "common.h"
41 #include "threads.h"
42 #include "mtime.h"
43 #include "tests.h"
44 #include "modules.h"
45
46 #include "stream_control.h"
47 #include "input_ext-intf.h"
48
49 #include "intf_msg.h"
50 #include "interface.h"
51
52 #include "gnome_sys.h"
53 #include "gnome_callbacks.h"
54 #include "gnome_interface.h"
55 #include "gnome_support.h"
56
57 #include "main.h"
58
59 /*****************************************************************************
60  * Local prototypes.
61  *****************************************************************************/
62 static int  intf_Probe     ( probedata_t *p_data );
63 static int  intf_Open      ( intf_thread_t *p_intf );
64 static void intf_Close     ( intf_thread_t *p_intf );
65 static void intf_Run       ( intf_thread_t *p_intf );
66
67 static gint GnomeManage    ( gpointer p_data );
68 static gint GnomeLanguageMenus( gpointer, GtkWidget *, es_descriptor_t *, gint,
69                               void (*pf_toggle)(GtkCheckMenuItem *, gpointer) );
70 static gint GnomeChapterMenu  ( gpointer, GtkWidget *,
71                               void (*pf_toggle)(GtkCheckMenuItem *, gpointer) );
72 static gint GnomeTitleMenu    ( gpointer, GtkWidget *, 
73                               void (*pf_toggle)(GtkCheckMenuItem *, gpointer) );
74 static gint GnomeSetupMenu    ( intf_thread_t * p_intf );
75
76 /*****************************************************************************
77  * g_atexit: kludge to avoid the Gnome thread to segfault at exit
78  *****************************************************************************
79  * gtk_init() makes several calls to g_atexit() which calls atexit() to
80  * register tidying callbacks to be called at program exit. Since the Gnome
81  * plugin is likely to be unloaded at program exit, we have to export this
82  * symbol to intercept the g_atexit() calls. Talk about crude hack.
83  *****************************************************************************/
84 void g_atexit( GVoidFunc func )
85 {
86     intf_thread_t *p_intf = p_main->p_intf;
87
88     if( p_intf->p_sys->pf_gdk_callback == NULL )
89     {
90         p_intf->p_sys->pf_gdk_callback = func;
91     }
92     else if( p_intf->p_sys->pf_gtk_callback == NULL )
93     {
94         p_intf->p_sys->pf_gtk_callback = func;
95     }
96     /* else nothing, but we could do something here */
97     return;
98 }
99
100 /*****************************************************************************
101  * Functions exported as capabilities. They are declared as static so that
102  * we don't pollute the namespace too much.
103  *****************************************************************************/
104 void _M( intf_getfunctions )( function_list_t * p_function_list )
105 {
106     p_function_list->pf_probe = intf_Probe;
107     p_function_list->functions.intf.pf_open  = intf_Open;
108     p_function_list->functions.intf.pf_close = intf_Close;
109     p_function_list->functions.intf.pf_run   = intf_Run;
110 }
111
112 /*****************************************************************************
113  * intf_Probe: probe the interface and return a score
114  *****************************************************************************
115  * This function tries to initialize Gnome and returns a score to the
116  * plugin manager so that it can select the best plugin.
117  *****************************************************************************/
118 static int intf_Probe( probedata_t *p_data )
119 {
120     if( TestMethod( INTF_METHOD_VAR, "gnome" ) )
121     {
122         return( 999 );
123     }
124
125     return( 100 );
126 }
127
128 /*****************************************************************************
129  * intf_Open: initialize and create window
130  *****************************************************************************/
131 static int intf_Open( intf_thread_t *p_intf )
132 {
133     /* Allocate instance and initialize some members */
134     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
135     if( p_intf->p_sys == NULL )
136     {
137         intf_ErrMsg("error: %s", strerror(ENOMEM));
138         return( 1 );
139     }
140
141     /* Initialize Gnome thread */
142     p_intf->p_sys->b_popup_changed = 0;
143     p_intf->p_sys->b_window_changed = 0;
144     p_intf->p_sys->b_playlist_changed = 0;
145     p_intf->p_sys->b_menus_update = 1;
146
147     p_intf->p_sys->b_scale_isfree = 1;
148
149     p_intf->p_sys->pf_gtk_callback = NULL;
150     p_intf->p_sys->pf_gdk_callback = NULL;
151
152     /* Initialize lock */
153     vlc_mutex_init( &p_intf->p_sys->change_lock );
154
155     return( 0 );
156 }
157
158 /*****************************************************************************
159  * intf_Close: destroy interface window
160  *****************************************************************************/
161 static void intf_Close( intf_thread_t *p_intf )
162 {
163     /* Destroy lock */
164     vlc_mutex_destroy( &p_intf->p_sys->change_lock );
165
166     /* Destroy structure */
167     free( p_intf->p_sys );
168 }
169
170 /*****************************************************************************
171  * intf_Run: Gnome thread
172  *****************************************************************************
173  * this part of the interface is in a separate thread so that we can call
174  * gtk_main() from within it without annoying the rest of the program.
175  * XXX: the approach may look kludgy, and probably is, but I could not find
176  * a better way to dynamically load a Gnome interface at runtime.
177  *****************************************************************************/
178 static void intf_Run( intf_thread_t *p_intf )
179 {
180     /* gnome_init needs to know the command line. We don't care, so we
181      * give it an empty one */
182     char *p_args[] = { "" };
183
184     /* The data types we are allowed to receive */
185     static GtkTargetEntry target_table[] =
186     {
187         { "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST },
188         { "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN }
189     };
190
191     /* Initialize Gnome */
192     gnome_init( p_main->psz_arg0, VERSION, 1, p_args );
193
194     /* Create some useful widgets that will certainly be used */
195     p_intf->p_sys->p_window = create_intf_window( );
196     p_intf->p_sys->p_popup = create_intf_popup( );
197
198     /* Set the title of the main window */
199     gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
200                           VOUT_TITLE " (Gnome interface)");
201
202     /* Accept file drops on the main window */
203     gtk_drag_dest_set( GTK_WIDGET( p_intf->p_sys->p_window ),
204                        GTK_DEST_DEFAULT_ALL, target_table,
205                        1, GDK_ACTION_COPY );
206
207     /* We don't create these ones yet because we perhaps won't need them */
208     p_intf->p_sys->p_about = NULL;
209     p_intf->p_sys->p_playlist = NULL;
210     p_intf->p_sys->p_modules = NULL;
211     p_intf->p_sys->p_fileopen = NULL;
212     p_intf->p_sys->p_disc = NULL;
213
214     /* Store p_intf to keep an eye on it */
215     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
216                          "p_intf", p_intf );
217
218     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup),
219                          "p_intf", p_intf );
220
221     /* Show the control window */
222     gtk_widget_show( p_intf->p_sys->p_window );
223
224     /* Sleep to avoid using all CPU - since some interfaces needs to access
225      * keyboard events, a 100ms delay is a good compromise */
226     p_intf->p_sys->i_timeout = gtk_timeout_add( INTF_IDLE_SLEEP / 1000,
227                                                 GnomeManage, p_intf );
228  
229
230     /* Enter gnome mode */
231     gtk_main();
232
233     /* launch stored callbacks */
234     if( p_intf->p_sys->pf_gtk_callback != NULL )
235     {
236         p_intf->p_sys->pf_gtk_callback();
237
238         if( p_intf->p_sys->pf_gdk_callback != NULL )
239         {
240             p_intf->p_sys->pf_gdk_callback();
241         }
242     }
243 }
244
245 /* following functions are local */
246
247 /*****************************************************************************
248  * GnomeManage: manage main thread messages
249  *****************************************************************************
250  * In this function, called approx. 10 times a second, we check what the
251  * main program wanted to tell us.
252  *****************************************************************************/
253 static gint GnomeManage( gpointer p_data )
254 {
255     intf_thread_t *p_intf = (void *)p_data;
256
257     vlc_mutex_lock( &p_intf->p_sys->change_lock );
258
259     /* If the "display popup" flag has changed */
260     if( p_intf->b_menu_change )
261     {
262         gnome_popup_menu_do_popup( p_intf->p_sys->p_popup,
263                                    NULL, NULL, NULL, NULL );
264         p_intf->b_menu_change = 0;
265     }
266
267     /* Update language/chapter menus after user request */
268     if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL &&
269         p_intf->p_sys->b_menus_update )
270     {
271         GnomeSetupMenu( p_intf );
272     }
273
274     /* Manage the slider */
275     if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL
276          && p_intf->p_sys->b_scale_isfree )
277     {
278         GtkWidget *p_scale;
279         GtkAdjustment *p_adj;
280    
281         p_scale = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
282                                   p_intf->p_sys->p_window ), "hscale" ) );
283         p_adj = gtk_range_get_adjustment ( GTK_RANGE( p_scale ) );
284
285         /* Update the value */
286         p_adj->value = ( 100. *
287                          p_intf->p_input->stream.p_selected_area->i_tell ) /
288                          p_intf->p_input->stream.p_selected_area->i_size;
289
290         /* Gtv does it this way. Why not. */
291         gtk_range_set_adjustment ( GTK_RANGE( p_scale ), p_adj );
292         gtk_range_slider_update ( GTK_RANGE( p_scale ) );
293         gtk_range_clear_background ( GTK_RANGE( p_scale ) );
294         gtk_range_draw_background ( GTK_RANGE( p_scale ) );
295     }
296
297     /* Manage core vlc functions through the callback */
298     p_intf->pf_manage( p_intf );
299
300     if( p_intf->b_die )
301     {
302         /* Make sure we won't be called again */
303         gtk_timeout_remove( p_intf->p_sys->i_timeout );
304
305         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
306
307         /* Prepare to die, young Skywalker */
308         gtk_main_quit();
309         return( FALSE );
310     }
311
312     vlc_mutex_unlock( &p_intf->p_sys->change_lock );
313
314     return( TRUE );
315 }
316
317 /*****************************************************************************
318  * GnomeLanguageMenus: update interactive menus of the interface
319  *****************************************************************************
320  * Sets up menus with information from input:
321  *  -languages
322  *  -sub-pictures
323  * Warning: since this function is designed to be called by management
324  * function, the interface lock has to be taken
325  *****************************************************************************/
326 static gint GnomeLanguageMenus( gpointer          p_data,
327                                 GtkWidget *       p_root,
328                                 es_descriptor_t * p_es,
329                                 gint              i_type,
330                           void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
331 {
332     intf_thread_t *     p_intf;
333     GtkWidget *         p_menu;
334     GtkWidget *         p_separator;
335     GtkWidget *         p_item;
336     GtkWidget *         p_item_off;
337     GSList *            p_group;
338     char *              psz_name;
339     gint                b_active;
340     gint                b_audio;
341     gint                b_spu;
342     gint                i;
343
344     
345
346     /* cast */
347     p_intf = (intf_thread_t *)p_data;
348
349     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
350
351     /* removes previous menu */
352     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
353
354     b_audio = ( i_type == 1 );
355     p_group = NULL;
356
357     /* menu container */
358     p_menu = gtk_menu_new();
359
360     /* special case for "off" item */
361     b_active = ( p_es == NULL ) ? TRUE : FALSE;
362     psz_name = "Off";
363
364     p_item_off = gtk_radio_menu_item_new_with_label( p_group, psz_name );
365     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item_off ) );
366     gtk_widget_show( p_item_off );
367     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_off ),
368                                     b_active );
369     gtk_menu_append( GTK_MENU( p_menu ), p_item_off );
370
371     p_separator = gtk_menu_item_new();
372     gtk_widget_show( p_separator );
373     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
374     gtk_widget_set_sensitive( p_separator, FALSE );
375
376     /* create a set of language buttons and append them to the container */
377     for( i = 0 ; i < p_intf->p_input->stream.i_es_number ; i++ )
378     {
379
380         b_audio = ( i_type == 1 ) && p_intf->p_input->stream.pp_es[i]->b_audio;
381         b_spu   = ( i_type == 2 ) && p_intf->p_input->stream.pp_es[i]->b_spu;
382
383         if( b_audio || b_spu )
384         {
385             b_active = ( p_es == p_intf->p_input->stream.pp_es[i] ) ? TRUE :
386                                                                       FALSE;
387             psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
388
389             p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
390             p_group =
391                 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
392             gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item ),
393                                             b_active );
394             gtk_menu_append( GTK_MENU( p_menu ), p_item );
395             gtk_widget_show( p_item );
396
397             /* setup signal hanling */
398             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
399                             GTK_SIGNAL_FUNC( pf_toggle ),
400                             (gpointer)( p_intf->p_input->stream.pp_es[i] ) );
401
402         }
403     }
404
405     /* signal hanling for off - dunno why this does not work
406      * if it is before the loop */
407     gtk_signal_connect( GTK_OBJECT( p_item_off ), "toggled",
408                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
409
410     /* link the new menu to the menubar item */
411     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
412
413     /* be sure that menu is sensitive */
414     gtk_widget_set_sensitive( p_root, TRUE );
415
416     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
417
418     return TRUE;
419 }
420
421 /*****************************************************************************
422  * GnomeChapterMenu: generate chapter menu for current title
423  *****************************************************************************/
424 static gint GnomeChapterMenu( gpointer p_data, GtkWidget * p_chapter,
425                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
426 {
427     intf_thread_t *     p_intf;
428     char                psz_name[10];
429     GtkWidget *         p_chapter_menu;
430     GtkWidget *         p_item;
431     GSList *            p_chapter_group;
432     gint                i_title;
433     gint                i_chapter;
434     gint                b_active;
435
436     /* cast */
437     p_intf = (intf_thread_t*)p_data;
438
439     /* removes previous menu */
440     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_chapter ) );
441
442     p_chapter_group = NULL;
443
444     i_title = p_intf->p_input->stream.p_selected_area->i_id;
445     p_chapter_menu = gtk_menu_new();
446
447     for( i_chapter = 0;
448          i_chapter < p_intf->p_input->stream.pp_areas[i_title]->i_part_nb ;
449          i_chapter++ )
450     {
451         b_active = ( p_intf->p_input->stream.pp_areas[i_title]->i_part
452                      == i_chapter + 1 ) ? 1 : 0;
453         
454         sprintf( psz_name, "Chapter %d", i_chapter + 1 );
455
456         p_item = gtk_radio_menu_item_new_with_label( p_chapter_group,
457                                                      psz_name );
458         p_chapter_group =
459             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
460         gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
461         gtk_widget_show( p_item );
462         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item ),
463                                         b_active );
464
465         /* setup signal hanling */
466         gtk_signal_connect( GTK_OBJECT( p_item ),
467                         "toggled",
468                         GTK_SIGNAL_FUNC( pf_toggle ),
469                         (gpointer)(i_chapter + 1) );
470     }
471
472     /* link the new menu to the title menu item */
473     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter ),
474                                p_chapter_menu );
475
476     /* be sure that chapter menu is sensitive */
477     gtk_widget_set_sensitive( p_chapter, TRUE );
478
479     return TRUE;
480 }
481
482 /*****************************************************************************
483  * GnomeTitleMenu: sets menus for titles and chapters selection
484  *****************************************************************************
485  * Generates two types of menus:
486  *  -simple list of titles
487  *  -cascaded lists of chapters for each title
488  *****************************************************************************/
489 static gint GnomeTitleMenu( gpointer       p_data,
490                             GtkWidget *    p_navigation, 
491                             void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
492 {
493     intf_thread_t *     p_intf;
494     char                psz_name[10];
495     GtkWidget *         p_title_menu;
496     GtkWidget *         p_title_item;
497     GtkWidget *         p_chapter_menu;
498     GtkWidget *         p_item;
499     GSList *            p_title_group;
500     GSList *            p_chapter_group;
501     gint                i_title;
502     gint                i_chapter;
503     gint                b_active;
504
505     /* cast */
506     p_intf = (intf_thread_t*)p_data;
507
508     p_title_menu = gtk_menu_new();
509     p_title_group = NULL;
510     p_chapter_group = NULL;
511
512     /* loop on titles */
513     for( i_title = 1 ;
514          i_title < p_intf->p_input->stream.i_area_nb ;
515          i_title++ )
516     {
517         b_active = ( p_intf->p_input->stream.pp_areas[i_title] ==
518                      p_intf->p_input->stream.p_selected_area ) ? 1 : 0;
519         sprintf( psz_name, "Title %d", i_title );
520
521         p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
522                                                            psz_name );
523         p_title_group =
524             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
525         gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
526         gtk_widget_show( p_title_item );
527
528                                            
529
530         if( pf_toggle == on_menubar_title_toggle )
531         {
532
533             gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_title_item ),
534                                         b_active );
535             /* setup signal hanling */
536             gtk_signal_connect( GTK_OBJECT( p_title_item ),
537                      "toggled",
538                      GTK_SIGNAL_FUNC( pf_toggle ),
539                      (gpointer)(p_intf->p_input->stream.pp_areas[i_title]) );
540         }
541         else
542         {
543             p_chapter_menu = gtk_menu_new();
544     
545             for( i_chapter = 0;
546                  i_chapter <
547                         p_intf->p_input->stream.pp_areas[i_title]->i_part_nb ;
548                  i_chapter++ )
549             {
550                 b_active = ( p_intf->p_input->stream.pp_areas[i_title]->i_part
551                              == i_chapter + 1 ) ? 1 : 0;
552                 
553                 sprintf( psz_name, "Chapter %d", i_chapter + 1 );
554     
555                 p_item = gtk_radio_menu_item_new_with_label(
556                                                 p_chapter_group, psz_name );
557                 p_chapter_group = gtk_radio_menu_item_group(
558                                                 GTK_RADIO_MENU_ITEM( p_item ) );
559                 gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
560                 gtk_widget_show( p_item );
561                 gtk_check_menu_item_set_active(
562                                     GTK_CHECK_MENU_ITEM( p_item ), b_active );
563
564                 /* setup signal hanling */
565                 gtk_signal_connect( GTK_OBJECT( p_item ),
566                            "toggled",
567                            GTK_SIGNAL_FUNC( pf_toggle ),
568                            (gpointer)( ( i_title * 100 ) + ( i_chapter + 1) ) );
569         }
570
571         /* link the new menu to the title menu item */
572         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
573                                    p_chapter_menu );
574         }
575
576         /* be sure that chapter menu is sensitive */
577         gtk_widget_set_sensitive( p_title_menu, TRUE );
578
579     }
580
581     /* link the new menu to the menubar item */
582     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
583
584     /* be sure that menu is sensitive */
585     gtk_widget_set_sensitive( p_navigation, TRUE );
586
587
588     return TRUE;
589 }
590
591 /*****************************************************************************
592  * GnomeSetupMenu: function that generates title/chapter/audio/subpic
593  * menus with help from preceding functions
594  *****************************************************************************/
595 static gint GnomeSetupMenu( intf_thread_t * p_intf )
596 {
597     es_descriptor_t *   p_audio_es;
598     es_descriptor_t *   p_spu_es;
599     GtkWidget *         p_menubar_menu;
600     GtkWidget *         p_popup_menu;
601     gint                i;
602
603     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
604                  p_intf->p_sys->p_window ), "menubar_title" ) );
605
606     GnomeTitleMenu( p_intf, p_menubar_menu, on_menubar_title_toggle );
607
608     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
609                  p_intf->p_sys->p_window ), "menubar_chapter" ) );
610
611     GnomeChapterMenu( p_intf, p_menubar_menu, on_menubar_chapter_toggle );
612
613     p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
614                  p_intf->p_sys->p_popup ), "popup_navigation" ) );
615
616     GnomeTitleMenu( p_intf, p_popup_menu, on_popup_navigation_toggle );
617
618     /* look for selected ES */
619     p_audio_es = NULL;
620     p_spu_es = NULL;
621
622     for( i = 0 ; i < p_intf->p_input->stream.i_selected_es_number ; i++ )
623     {
624         if( p_intf->p_input->stream.pp_es[i]->b_audio )
625         {
626             p_audio_es = p_intf->p_input->stream.pp_es[i];
627         }
628
629         if( p_intf->p_input->stream.pp_es[i]->b_spu )
630         {
631             p_spu_es = p_intf->p_input->stream.pp_es[i];
632         }
633     }
634
635     /* audio menus */
636
637     /* find audio root menu */
638     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
639                          p_intf->p_sys->p_window ), "menubar_audio" ) );
640
641     p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
642                  p_intf->p_sys->p_popup ), "popup_audio" ) );
643
644     GnomeLanguageMenus( p_intf, p_menubar_menu, p_audio_es, 1,
645                       on_menubar_audio_toggle );
646     GnomeLanguageMenus( p_intf, p_popup_menu, p_audio_es, 1,
647                       on_popup_audio_toggle );
648
649     /* sub picture menus */
650
651     /* find spu root menu */
652     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
653                       p_intf->p_sys->p_window ), "menubar_subtitle" ) );
654
655     p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
656                  p_intf->p_sys->p_popup ), "popup_subtitle" ) );
657
658     GnomeLanguageMenus( p_intf, p_menubar_menu, p_spu_es, 2,
659                       on_menubar_subtitle_toggle  );
660     GnomeLanguageMenus( p_intf, p_popup_menu, p_spu_es, 2,
661                       on_popup_subtitle_toggle );
662
663     /* everything is ready */
664     p_intf->p_sys->b_menus_update = 0;
665
666     return TRUE;
667 }