]> git.sesse.net Git - vlc/blob - plugins/gnome/intf_gnome.c
* Bug fixes and enhancements in the Gtk+/Gnome interfaces.
[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.22 2001/03/15 01:42:19 sam 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_callbacks.h"
53 #include "gnome_interface.h"
54 #include "gnome_support.h"
55 #include "intf_gnome.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 static void GnomeDisplayDate  ( GtkAdjustment *p_adj );
76
77 /*****************************************************************************
78  * g_atexit: kludge to avoid the Gnome thread to segfault at exit
79  *****************************************************************************
80  * gtk_init() makes several calls to g_atexit() which calls atexit() to
81  * register tidying callbacks to be called at program exit. Since the Gnome
82  * plugin is likely to be unloaded at program exit, we have to export this
83  * symbol to intercept the g_atexit() calls. Talk about crude hack.
84  *****************************************************************************/
85 void g_atexit( GVoidFunc func )
86 {
87     intf_thread_t *p_intf = p_main->p_intf;
88
89     if( p_intf->p_sys->pf_gdk_callback == NULL )
90     {
91         p_intf->p_sys->pf_gdk_callback = func;
92     }
93     else if( p_intf->p_sys->pf_gtk_callback == NULL )
94     {
95         p_intf->p_sys->pf_gtk_callback = func;
96     }
97     /* else nothing, but we could do something here */
98     return;
99 }
100
101 /*****************************************************************************
102  * Functions exported as capabilities. They are declared as static so that
103  * we don't pollute the namespace too much.
104  *****************************************************************************/
105 void _M( intf_getfunctions )( function_list_t * p_function_list )
106 {
107     p_function_list->pf_probe = intf_Probe;
108     p_function_list->functions.intf.pf_open  = intf_Open;
109     p_function_list->functions.intf.pf_close = intf_Close;
110     p_function_list->functions.intf.pf_run   = intf_Run;
111 }
112
113 /*****************************************************************************
114  * intf_Probe: probe the interface and return a score
115  *****************************************************************************
116  * This function tries to initialize Gnome and returns a score to the
117  * plugin manager so that it can select the best plugin.
118  *****************************************************************************/
119 static int intf_Probe( probedata_t *p_data )
120 {
121     if( TestMethod( INTF_METHOD_VAR, "gnome" ) )
122     {
123         return( 999 );
124     }
125
126     return( 100 );
127 }
128
129 /*****************************************************************************
130  * intf_Open: initialize and create window
131  *****************************************************************************/
132 static int intf_Open( intf_thread_t *p_intf )
133 {
134     /* Allocate instance and initialize some members */
135     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
136     if( p_intf->p_sys == NULL )
137     {
138         intf_ErrMsg("error: %s", strerror(ENOMEM));
139         return( 1 );
140     }
141
142     /* Initialize Gnome thread */
143     p_intf->p_sys->b_popup_changed = 0;
144     p_intf->p_sys->b_window_changed = 0;
145     p_intf->p_sys->b_playlist_changed = 0;
146     p_intf->p_sys->b_menus_update = 1;
147
148     p_intf->p_sys->b_slider_free = 1;
149
150     p_intf->p_sys->pf_gtk_callback = NULL;
151     p_intf->p_sys->pf_gdk_callback = NULL;
152
153     return( 0 );
154 }
155
156 /*****************************************************************************
157  * intf_Close: destroy interface window
158  *****************************************************************************/
159 static void intf_Close( intf_thread_t *p_intf )
160 {
161     /* Destroy structure */
162     free( p_intf->p_sys );
163 }
164
165 /*****************************************************************************
166  * intf_Run: Gnome thread
167  *****************************************************************************
168  * this part of the interface is in a separate thread so that we can call
169  * gtk_main() from within it without annoying the rest of the program.
170  * XXX: the approach may look kludgy, and probably is, but I could not find
171  * a better way to dynamically load a Gnome interface at runtime.
172  *****************************************************************************/
173 static void intf_Run( intf_thread_t *p_intf )
174 {
175     /* gnome_init needs to know the command line. We don't care, so we
176      * give it an empty one */
177     char *p_args[] = { "" };
178     int   i_args   = 1;
179
180     /* The data types we are allowed to receive */
181     static GtkTargetEntry target_table[] =
182     {
183         { "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST },
184         { "text/plain",    0, DROP_ACCEPT_TEXT_PLAIN }
185     };
186
187     /* intf_Manage callback timeout */
188     int i_timeout;
189
190     /* Initialize Gnome */
191     gnome_init( p_main->psz_arg0, VERSION, i_args, p_args );
192
193     /* Create some useful widgets that will certainly be used */
194     p_intf->p_sys->p_window = create_intf_window( );
195     p_intf->p_sys->p_popup = create_intf_popup( );
196     p_intf->p_sys->p_disc = create_intf_disc( );
197     p_intf->p_sys->p_network = create_intf_network( );
198
199     /* Set the title of the main window */
200     gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
201                           VOUT_TITLE " (Gnome interface)");
202
203     /* Accept file drops on the main window */
204     gtk_drag_dest_set( GTK_WIDGET( p_intf->p_sys->p_window ),
205                        GTK_DEST_DEFAULT_ALL, target_table,
206                        1, GDK_ACTION_COPY );
207
208     /* Get the interface labels */
209     #define P_LABEL( name ) GTK_LABEL( gtk_object_get_data( \
210                          GTK_OBJECT( p_intf->p_sys->p_window ), name ) )
211     p_intf->p_sys->p_label_date = P_LABEL( "label_date" );
212     p_intf->p_sys->p_label_status = P_LABEL( "label_status" );
213     #undef P_LABEL
214
215     /* Connect the date display to the slider */
216     #define P_SLIDER GTK_RANGE( gtk_object_get_data( \
217                          GTK_OBJECT( p_intf->p_sys->p_window ), "slider" ) )
218     p_intf->p_sys->p_adj = gtk_range_get_adjustment( P_SLIDER );
219
220     gtk_signal_connect ( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed",
221                          GTK_SIGNAL_FUNC( GnomeDisplayDate ), NULL );
222     p_intf->p_sys->f_adj_oldvalue = 0;
223     #undef P_SLIDER
224
225     /* We don't create these ones yet because we perhaps won't need them */
226     p_intf->p_sys->p_about = NULL;
227     p_intf->p_sys->p_playlist = NULL;
228     p_intf->p_sys->p_modules = NULL;
229     p_intf->p_sys->p_fileopen = NULL;
230
231     /* Store p_intf to keep an eye on it */
232     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
233                          "p_intf", p_intf );
234
235     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup),
236                          "p_intf", p_intf );
237
238     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_disc),
239                          "p_intf", p_intf );
240
241     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_network),
242                          "p_intf", p_intf );
243
244     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_adj),
245                          "p_intf", p_intf );
246
247     /* Show the control window */
248     gtk_widget_show( p_intf->p_sys->p_window );
249
250     /* Sleep to avoid using all CPU - since some interfaces needs to access
251      * keyboard events, a 100ms delay is a good compromise */
252     i_timeout = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, GnomeManage, p_intf );
253
254     /* Enter gnome mode */
255     gtk_main();
256
257     /* Remove the timeout */
258     gtk_timeout_remove( i_timeout );
259
260     /* Get rid of stored callbacks so we can unload the plugin */
261     if( p_intf->p_sys->pf_gtk_callback != NULL )
262     {
263         p_intf->p_sys->pf_gtk_callback( );
264         p_intf->p_sys->pf_gtk_callback = NULL;
265
266     }
267
268     if( p_intf->p_sys->pf_gdk_callback != NULL )
269     {
270         p_intf->p_sys->pf_gdk_callback( );
271         p_intf->p_sys->pf_gdk_callback = NULL;
272     }
273 }
274
275 /* following functions are local */
276
277 /*****************************************************************************
278  * GnomeManage: manage main thread messages
279  *****************************************************************************
280  * In this function, called approx. 10 times a second, we check what the
281  * main program wanted to tell us.
282  *****************************************************************************/
283 static gint GnomeManage( gpointer p_data )
284 {
285 #define p_intf ((intf_thread_t *)p_data)
286
287     vlc_mutex_lock( &p_intf->change_lock );
288
289     /* If the "display popup" flag has changed */
290     if( p_intf->b_menu_change )
291     {
292         gnome_popup_menu_do_popup( p_intf->p_sys->p_popup,
293                                    NULL, NULL, NULL, NULL );
294         p_intf->b_menu_change = 0;
295     }
296
297     /* Update language/chapter menus after user request */
298     if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL &&
299         p_intf->p_sys->b_menus_update )
300     {
301         GnomeSetupMenu( p_intf );
302     }
303
304     /* Manage the slider */
305     if( p_intf->p_input != NULL )
306     {
307         float newvalue = p_intf->p_sys->p_adj->value;
308
309 #define p_area p_intf->p_input->stream.p_selected_area
310         /* If the user hasn't touched the slider since the last time,
311          * then the input can safely change it */
312         if( newvalue == p_intf->p_sys->f_adj_oldvalue )
313         {
314             /* Update the value */
315             p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue =
316                 ( 100. * p_area->i_tell ) / p_area->i_size;
317
318             gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
319                                      "value_changed" );
320         }
321         /* Otherwise, send message to the input if the user has
322          * finished dragging the slider */
323         else if( p_intf->p_sys->b_slider_free )
324         {
325             off_t i_seek = ( newvalue * p_area->i_size ) / 100;
326
327             input_Seek( p_intf->p_input, i_seek );
328
329             /* Update the old value */
330             p_intf->p_sys->f_adj_oldvalue = newvalue;
331         }
332 #undef p_area
333     }
334
335     /* Manage core vlc functions through the callback */
336     p_intf->pf_manage( p_intf );
337
338     if( p_intf->b_die )
339     {
340         vlc_mutex_unlock( &p_intf->change_lock );
341
342         /* Prepare to die, young Skywalker */
343         gtk_main_quit();
344
345         /* Just in case */
346         return( FALSE );
347     }
348
349     vlc_mutex_unlock( &p_intf->change_lock );
350
351     return( TRUE );
352
353 #undef p_intf
354 }
355
356 /*****************************************************************************
357  * GnomeLanguageMenus: update interactive menus of the interface
358  *****************************************************************************
359  * Sets up menus with information from input:
360  *  -languages
361  *  -sub-pictures
362  * Warning: since this function is designed to be called by management
363  * function, the interface lock has to be taken
364  *****************************************************************************/
365 static gint GnomeLanguageMenus( gpointer          p_data,
366                                 GtkWidget *       p_root,
367                                 es_descriptor_t * p_es,
368                                 gint              i_type,
369                           void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
370 {
371     intf_thread_t *     p_intf;
372     GtkWidget *         p_menu;
373     GtkWidget *         p_separator;
374     GtkWidget *         p_item;
375     GtkWidget *         p_item_off;
376     GSList *            p_group;
377     char *              psz_name;
378     gint                b_active;
379     gint                b_audio;
380     gint                b_spu;
381     gint                i;
382
383     
384
385     /* cast */
386     p_intf = (intf_thread_t *)p_data;
387
388     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
389
390     /* removes previous menu */
391     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) );
392
393     b_audio = ( i_type == 1 );
394     p_group = NULL;
395
396     /* menu container */
397     p_menu = gtk_menu_new();
398
399     /* special case for "off" item */
400     b_active = ( p_es == NULL ) ? TRUE : FALSE;
401     psz_name = "Off";
402
403     p_item_off = gtk_radio_menu_item_new_with_label( p_group, psz_name );
404     p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item_off ) );
405     gtk_widget_show( p_item_off );
406     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_off ),
407                                     b_active );
408     gtk_menu_append( GTK_MENU( p_menu ), p_item_off );
409
410     p_separator = gtk_menu_item_new();
411     gtk_widget_show( p_separator );
412     gtk_menu_append( GTK_MENU( p_menu ), p_separator );
413     gtk_widget_set_sensitive( p_separator, FALSE );
414
415     /* create a set of language buttons and append them to the container */
416     for( i = 0 ; i < p_intf->p_input->stream.i_es_number ; i++ )
417     {
418
419         b_audio = ( i_type == 1 ) && p_intf->p_input->stream.pp_es[i]->b_audio;
420         b_spu   = ( i_type == 2 ) && p_intf->p_input->stream.pp_es[i]->b_spu;
421
422         if( b_audio || b_spu )
423         {
424             b_active = ( p_es == p_intf->p_input->stream.pp_es[i] ) ? TRUE :
425                                                                       FALSE;
426             psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
427
428             p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
429             p_group =
430                 gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
431             gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item ),
432                                             b_active );
433             gtk_menu_append( GTK_MENU( p_menu ), p_item );
434             gtk_widget_show( p_item );
435
436             /* setup signal hanling */
437             gtk_signal_connect( GTK_OBJECT( p_item ), "toggled",
438                             GTK_SIGNAL_FUNC( pf_toggle ),
439                             (gpointer)( p_intf->p_input->stream.pp_es[i] ) );
440
441         }
442     }
443
444     /* signal hanling for off - dunno why this does not work
445      * if it is before the loop */
446     gtk_signal_connect( GTK_OBJECT( p_item_off ), "toggled",
447                         GTK_SIGNAL_FUNC ( pf_toggle ), NULL );
448
449     /* link the new menu to the menubar item */
450     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu );
451
452     /* be sure that menu is sensitive */
453     gtk_widget_set_sensitive( p_root, TRUE );
454
455     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
456
457     return TRUE;
458 }
459
460 /*****************************************************************************
461  * GnomeChapterMenu: generate chapter menu for current title
462  *****************************************************************************/
463 static gint GnomeChapterMenu( gpointer p_data, GtkWidget * p_chapter,
464                         void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
465 {
466     intf_thread_t *     p_intf;
467     char                psz_name[10];
468     GtkWidget *         p_chapter_menu;
469     GtkWidget *         p_item;
470     GSList *            p_chapter_group;
471     gint                i_title;
472     gint                i_chapter;
473     gint                b_active;
474
475     /* cast */
476     p_intf = (intf_thread_t*)p_data;
477
478     /* removes previous menu */
479     gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_chapter ) );
480
481     p_chapter_group = NULL;
482
483     i_title = p_intf->p_input->stream.p_selected_area->i_id;
484     p_chapter_menu = gtk_menu_new();
485
486     for( i_chapter = 0;
487          i_chapter < p_intf->p_input->stream.pp_areas[i_title]->i_part_nb ;
488          i_chapter++ )
489     {
490         b_active = ( p_intf->p_input->stream.pp_areas[i_title]->i_part
491                      == i_chapter + 1 ) ? 1 : 0;
492         
493         sprintf( psz_name, "Chapter %d", i_chapter + 1 );
494
495         p_item = gtk_radio_menu_item_new_with_label( p_chapter_group,
496                                                      psz_name );
497         p_chapter_group =
498             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
499         gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
500         gtk_widget_show( p_item );
501         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item ),
502                                         b_active );
503
504         /* setup signal hanling */
505         gtk_signal_connect( GTK_OBJECT( p_item ),
506                         "toggled",
507                         GTK_SIGNAL_FUNC( pf_toggle ),
508                         (gpointer)(i_chapter + 1) );
509     }
510
511     /* link the new menu to the title menu item */
512     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter ),
513                                p_chapter_menu );
514
515     /* be sure that chapter menu is sensitive */
516     gtk_widget_set_sensitive( p_chapter, TRUE );
517
518     return TRUE;
519 }
520
521 /*****************************************************************************
522  * GnomeTitleMenu: sets menus for titles and chapters selection
523  *****************************************************************************
524  * Generates two types of menus:
525  *  -simple list of titles
526  *  -cascaded lists of chapters for each title
527  *****************************************************************************/
528 static gint GnomeTitleMenu( gpointer       p_data,
529                             GtkWidget *    p_navigation, 
530                             void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
531 {
532     intf_thread_t *     p_intf;
533     char                psz_name[10];
534     GtkWidget *         p_title_menu;
535     GtkWidget *         p_title_item;
536     GtkWidget *         p_chapter_menu;
537     GtkWidget *         p_item;
538     GSList *            p_title_group;
539     GSList *            p_chapter_group;
540     gint                i_title;
541     gint                i_chapter;
542     gint                b_active;
543
544     /* cast */
545     p_intf = (intf_thread_t*)p_data;
546
547     p_title_menu = gtk_menu_new();
548     p_title_group = NULL;
549     p_chapter_group = NULL;
550
551     /* loop on titles */
552     for( i_title = 1 ;
553          i_title < p_intf->p_input->stream.i_area_nb ;
554          i_title++ )
555     {
556         b_active = ( p_intf->p_input->stream.pp_areas[i_title] ==
557                      p_intf->p_input->stream.p_selected_area ) ? 1 : 0;
558         sprintf( psz_name, "Title %d", i_title );
559
560         p_title_item = gtk_radio_menu_item_new_with_label( p_title_group,
561                                                            psz_name );
562         p_title_group =
563             gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) );
564         gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item );
565         gtk_widget_show( p_title_item );
566
567                                            
568
569         if( pf_toggle == on_menubar_title_toggle )
570         {
571
572             gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_title_item ),
573                                         b_active );
574             /* setup signal hanling */
575             gtk_signal_connect( GTK_OBJECT( p_title_item ),
576                      "toggled",
577                      GTK_SIGNAL_FUNC( pf_toggle ),
578                      (gpointer)(p_intf->p_input->stream.pp_areas[i_title]) );
579         }
580         else
581         {
582             p_chapter_menu = gtk_menu_new();
583     
584             for( i_chapter = 0;
585                  i_chapter <
586                         p_intf->p_input->stream.pp_areas[i_title]->i_part_nb ;
587                  i_chapter++ )
588             {
589                 b_active = ( p_intf->p_input->stream.pp_areas[i_title]->i_part
590                              == i_chapter + 1 ) ? 1 : 0;
591                 
592                 sprintf( psz_name, "Chapter %d", i_chapter + 1 );
593     
594                 p_item = gtk_radio_menu_item_new_with_label(
595                                                 p_chapter_group, psz_name );
596                 p_chapter_group = gtk_radio_menu_item_group(
597                                                 GTK_RADIO_MENU_ITEM( p_item ) );
598                 gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item );
599                 gtk_widget_show( p_item );
600                 gtk_check_menu_item_set_active(
601                                     GTK_CHECK_MENU_ITEM( p_item ), b_active );
602
603                 /* setup signal hanling */
604                 gtk_signal_connect( GTK_OBJECT( p_item ),
605                            "toggled",
606                            GTK_SIGNAL_FUNC( pf_toggle ),
607                            (gpointer)( ( i_title * 100 ) + ( i_chapter + 1) ) );
608         }
609
610         /* link the new menu to the title menu item */
611         gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ),
612                                    p_chapter_menu );
613         }
614
615         /* be sure that chapter menu is sensitive */
616         gtk_widget_set_sensitive( p_title_menu, TRUE );
617
618     }
619
620     /* link the new menu to the menubar item */
621     gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu );
622
623     /* be sure that menu is sensitive */
624     gtk_widget_set_sensitive( p_navigation, TRUE );
625
626
627     return TRUE;
628 }
629
630 /*****************************************************************************
631  * GnomeSetupMenu: function that generates title/chapter/audio/subpic
632  * menus with help from preceding functions
633  *****************************************************************************/
634 static gint GnomeSetupMenu( intf_thread_t * p_intf )
635 {
636     es_descriptor_t *   p_audio_es;
637     es_descriptor_t *   p_spu_es;
638     GtkWidget *         p_menubar_menu;
639     GtkWidget *         p_popup_menu;
640     gint                i;
641
642     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
643                  p_intf->p_sys->p_window ), "menubar_title" ) );
644
645     GnomeTitleMenu( p_intf, p_menubar_menu, on_menubar_title_toggle );
646
647     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
648                  p_intf->p_sys->p_window ), "menubar_chapter" ) );
649
650     GnomeChapterMenu( p_intf, p_menubar_menu, on_menubar_chapter_toggle );
651
652     p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
653                  p_intf->p_sys->p_popup ), "popup_navigation" ) );
654
655     GnomeTitleMenu( p_intf, p_popup_menu, on_popup_navigation_toggle );
656
657     /* look for selected ES */
658     p_audio_es = NULL;
659     p_spu_es = NULL;
660
661     for( i = 0 ; i < p_intf->p_input->stream.i_selected_es_number ; i++ )
662     {
663         if( p_intf->p_input->stream.pp_es[i]->b_audio )
664         {
665             p_audio_es = p_intf->p_input->stream.pp_es[i];
666         }
667
668         if( p_intf->p_input->stream.pp_es[i]->b_spu )
669         {
670             p_spu_es = p_intf->p_input->stream.pp_es[i];
671         }
672     }
673
674     /* audio menus */
675
676     /* find audio root menu */
677     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
678                          p_intf->p_sys->p_window ), "menubar_audio" ) );
679
680     p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
681                  p_intf->p_sys->p_popup ), "popup_audio" ) );
682
683     GnomeLanguageMenus( p_intf, p_menubar_menu, p_audio_es, 1,
684                       on_menubar_audio_toggle );
685     GnomeLanguageMenus( p_intf, p_popup_menu, p_audio_es, 1,
686                       on_popup_audio_toggle );
687
688     /* sub picture menus */
689
690     /* find spu root menu */
691     p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
692                       p_intf->p_sys->p_window ), "menubar_subtitle" ) );
693
694     p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( 
695                  p_intf->p_sys->p_popup ), "popup_subtitle" ) );
696
697     GnomeLanguageMenus( p_intf, p_menubar_menu, p_spu_es, 2,
698                       on_menubar_subtitle_toggle  );
699     GnomeLanguageMenus( p_intf, p_popup_menu, p_spu_es, 2,
700                       on_popup_subtitle_toggle );
701
702     /* everything is ready */
703     p_intf->p_sys->b_menus_update = 0;
704
705     return TRUE;
706 }
707
708 /*****************************************************************************
709  * GnomeDisplayDate: display stream date
710  *****************************************************************************
711  * This function displays the current date related to the position in
712  * the stream. It is called whenever the slider changes its value.
713  *****************************************************************************/
714 void GnomeDisplayDate( GtkAdjustment *p_adj )
715 {
716     intf_thread_t *p_intf;
717    
718     p_intf = gtk_object_get_data( GTK_OBJECT( p_adj ), "p_intf" );
719
720     if( p_intf->p_input != NULL )
721     {
722 #define p_area p_intf->p_input->stream.p_selected_area
723         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
724
725         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
726
727         gtk_label_set_text( p_intf->p_sys->p_label_date,
728                             input_OffsetToTime( p_intf->p_input, psz_time,
729                                    ( p_area->i_size * p_adj->value ) / 100 ) );
730
731         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
732 #undef p_area
733      }
734 }
735
736