X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fgtk%2Fintf_gtk.c;h=3398b810df73f4624466ae83f4f4f0bdaff6e2b3;hb=440f9992ee947ea5fd0debbf35fdd1011c6404b3;hp=d6db1ebf46cb3580a3e324b552acaa447767ebc3;hpb=5525a154c68037ac0c4102a999c8af95fff76047;p=vlc diff --git a/plugins/gtk/intf_gtk.c b/plugins/gtk/intf_gtk.c index d6db1ebf46..3398b810df 100644 --- a/plugins/gtk/intf_gtk.c +++ b/plugins/gtk/intf_gtk.c @@ -2,7 +2,7 @@ * intf_gtk.c: Gtk+ interface ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: intf_gtk.c,v 1.7 2001/03/08 15:48:14 octplane Exp $ + * $Id: intf_gtk.c,v 1.22 2001/05/30 17:03:12 sam Exp $ * * Authors: Samuel Hocevar * Stéphane Borel @@ -42,21 +42,29 @@ #include "threads.h" #include "mtime.h" #include "tests.h" -#include "modules.h" #include "stream_control.h" #include "input_ext-intf.h" -#include "intf_msg.h" #include "interface.h" +#include "intf_msg.h" +#include "intf_playlist.h" + +#include "video.h" +#include "video_output.h" -#include "gtk_sys.h" #include "gtk_callbacks.h" #include "gtk_interface.h" #include "gtk_support.h" +#include "gtk_menu.h" +#include "gtk_display.h" +#include "intf_gtk.h" #include "main.h" +#include "modules.h" +#include "modules_export.h" + /***************************************************************************** * Local prototypes. *****************************************************************************/ @@ -66,14 +74,6 @@ static void intf_Close ( intf_thread_t *p_intf ); static void intf_Run ( intf_thread_t *p_intf ); static gint GtkManage ( gpointer p_data ); -static gint GtkLanguageMenus( gpointer, GtkWidget *, es_descriptor_t *, gint, - void (*pf_activate)(GtkMenuItem *, gpointer) ); -static gint GtkChapterMenu ( gpointer, GtkWidget *, - void (*pf_activate)(GtkMenuItem *, gpointer) ); -static gint GtkTitleMenu ( gpointer, GtkWidget *, - void (*pf_activate)(GtkMenuItem *, gpointer) ); -void GtkPlayListManage( gpointer p_data ); - /***************************************************************************** * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit @@ -124,6 +124,11 @@ static int intf_Probe( probedata_t *p_data ) return( 999 ); } + if( TestProgram( "gvlc" ) ) + { + return( 190 ); + } + return( 90 ); } @@ -145,18 +150,12 @@ static int intf_Open( intf_thread_t *p_intf ) p_intf->p_sys->b_window_changed = 0; p_intf->p_sys->b_playlist_changed = 0; - p_intf->p_sys->b_menus_update = 1; - p_intf->p_sys->b_scale_isfree = 1; - - p_intf->p_sys->i_playing = -1; + p_intf->p_sys->b_slider_free = 1; p_intf->p_sys->pf_gtk_callback = NULL; p_intf->p_sys->pf_gdk_callback = NULL; - /* Initialize lock */ - vlc_mutex_init( &p_intf->p_sys->change_lock ); - return( 0 ); } @@ -165,9 +164,6 @@ static int intf_Open( intf_thread_t *p_intf ) *****************************************************************************/ static void intf_Close( intf_thread_t *p_intf ) { - /* Destroy lock */ - vlc_mutex_destroy( &p_intf->p_sys->change_lock ); - /* Destroy structure */ free( p_intf->p_sys ); } @@ -184,10 +180,9 @@ static void intf_Run( intf_thread_t *p_intf ) { /* gtk_init needs to know the command line. We don't care, so we * give it an empty one */ - char *p_args[] = { "" }; - char **pp_args = p_args; - int i_args = 1; - GtkWidget * temp; + char *p_args[] = { "" }; + char **pp_args = p_args; + int i_args = 1; /* The data types we are allowed to receive */ static GtkTargetEntry target_table[] = @@ -196,14 +191,16 @@ static void intf_Run( intf_thread_t *p_intf ) { "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN } }; + /* intf_Manage callback timeout */ + int i_timeout; + /* Initialize Gtk+ */ gtk_init( &i_args, &pp_args ); /* Create some useful widgets that will certainly be used */ p_intf->p_sys->p_window = create_intf_window( ); p_intf->p_sys->p_popup = create_intf_popup( ); - p_intf->p_sys->p_playlist = create_intf_playlist( ); - + p_intf->p_sys->p_playlist = create_intf_playlist(); /* Set the title of the main window */ gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window), @@ -215,18 +212,39 @@ static void intf_Run( intf_thread_t *p_intf ) 1, GDK_ACTION_COPY ); /* Accept file drops on the playlist window */ - temp = lookup_widget(p_intf->p_sys->p_playlist, "clist1"); - - - gtk_drag_dest_set( GTK_WIDGET( temp ), + gtk_drag_dest_set( GTK_WIDGET( lookup_widget( p_intf->p_sys->p_playlist, + "playlist_clist") ), GTK_DEST_DEFAULT_ALL, target_table, 1, GDK_ACTION_COPY ); + /* Get the interface labels */ + p_intf->p_sys->p_slider_frame = GTK_FRAME( gtk_object_get_data( + GTK_OBJECT(p_intf->p_sys->p_window ), "slider_frame" ) ); + +#define P_LABEL( name ) GTK_LABEL( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_window ), name ) ) + p_intf->p_sys->p_label_title = P_LABEL( "title_label" ); + p_intf->p_sys->p_label_chapter = P_LABEL( "chapter_label" ); +#undef P_LABEL + + /* Connect the date display to the slider */ +#define P_SLIDER GTK_RANGE( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_window ), "slider" ) ) + p_intf->p_sys->p_adj = gtk_range_get_adjustment( P_SLIDER ); + + gtk_signal_connect ( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed", + GTK_SIGNAL_FUNC( GtkDisplayDate ), NULL ); + p_intf->p_sys->f_adj_oldvalue = 0; +#undef P_SLIDER + /* We don't create these ones yet because we perhaps won't need them */ p_intf->p_sys->p_about = NULL; p_intf->p_sys->p_modules = NULL; p_intf->p_sys->p_fileopen = NULL; p_intf->p_sys->p_disc = NULL; + p_intf->p_sys->p_network = NULL; + p_intf->p_sys->p_preferences = NULL; + p_intf->p_sys->p_jump = NULL; /* Store p_intf to keep an eye on it */ gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window), @@ -235,25 +253,26 @@ static void intf_Run( intf_thread_t *p_intf ) gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup), "p_intf", p_intf ); - gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_playlist), + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_playlist ), "p_intf", p_intf ); - + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_adj), + "p_intf", p_intf ); /* Show the control window */ gtk_widget_show( p_intf->p_sys->p_window ); - /* Sleep to avoid using all CPU - since some interfaces needs to access * keyboard events, a 100ms delay is a good compromise */ - p_intf->p_sys->i_timeout = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, - GtkManage, p_intf ); - + i_timeout = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, GtkManage, p_intf ); /* Enter Gtk mode */ gtk_main(); - /* launch stored callbacks */ + /* Remove the timeout */ + gtk_timeout_remove( i_timeout ); + + /* Launch stored callbacks */ if( p_intf->p_sys->pf_gtk_callback != NULL ) { p_intf->p_sys->pf_gtk_callback(); @@ -273,15 +292,11 @@ static void intf_Run( intf_thread_t *p_intf ) * In this function, called approx. 10 times a second, we check what the * main program wanted to tell us. *****************************************************************************/ - static gint GtkManage( gpointer p_data ) { - intf_thread_t *p_intf = (void *)p_data; - - GtkPlayListManage( p_data ); - - vlc_mutex_lock( &p_intf->p_sys->change_lock ); +#define p_intf ((intf_thread_t *)p_data) + vlc_mutex_lock( &p_intf->change_lock ); /* If the "display popup" flag has changed */ if( p_intf->b_menu_change ) @@ -297,407 +312,84 @@ static gint GtkManage( gpointer p_data ) p_intf->b_menu_change = 0; } - /* Update language/chapter menus after user request */ - if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL && - p_intf->p_sys->b_menus_update ) - { - es_descriptor_t * p_audio_es; - es_descriptor_t * p_spu_es; - GtkWidget * p_menubar_menu; - GtkWidget * p_popup_menu; - gint i; - - p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_window ), "menubar_title" ) ); - - GtkTitleMenu( p_intf, p_menubar_menu, on_menubar_title_activate ); + /* update the playlist */ + GtkPlayListManage( p_data ); - p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_window ), "menubar_chapter" ) ); - - GtkChapterMenu( p_intf, p_menubar_menu, on_menubar_chapter_activate ); - - p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_popup ), "popup_navigation" ) ); + if( p_intf->p_input != NULL && !p_intf->b_die ) + { + vlc_mutex_lock( &p_intf->p_input->stream.stream_lock ); - GtkTitleMenu( p_intf, p_popup_menu, on_popup_navigation_activate ); - - /* look for selected ES */ - p_audio_es = NULL; - p_spu_es = NULL; + /* New input or stream map change */ + if( p_intf->p_input->stream.b_changed ) + { + GtkModeManage( p_intf ); + } - for( i = 0 ; i < p_intf->p_input->stream.i_selected_es_number ; i++ ) + /* Manage the slider */ + if( p_intf->p_input->stream.b_seekable ) { - if( p_intf->p_input->stream.pp_es[i]->b_audio ) + float newvalue = p_intf->p_sys->p_adj->value; + +#define p_area p_intf->p_input->stream.p_selected_area + /* If the user hasn't touched the slider since the last time, + * then the input can safely change it */ + if( newvalue == p_intf->p_sys->f_adj_oldvalue ) { - p_audio_es = p_intf->p_input->stream.pp_es[i]; - } + /* Update the value */ + p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue = + ( 100. * p_area->i_tell ) / p_area->i_size; - if( p_intf->p_input->stream.pp_es[i]->b_spu ) + gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ), + "value_changed" ); + } + /* Otherwise, send message to the input if the user has + * finished dragging the slider */ + else if( p_intf->p_sys->b_slider_free ) { - p_spu_es = p_intf->p_input->stream.pp_es[i]; + off_t i_seek = ( newvalue * p_area->i_size ) / 100; + + /* release the lock to be able to seek */ + vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock ); + input_Seek( p_intf->p_input, i_seek ); + vlc_mutex_lock( &p_intf->p_input->stream.stream_lock ); + + /* Update the old value */ + p_intf->p_sys->f_adj_oldvalue = newvalue; } +#undef p_area } + vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock ); - /* audio menus */ - - /* find audio root menu */ - p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_window ), "menubar_audio" ) ); - - p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_popup ), "popup_audio" ) ); - - GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, 1, - on_menubar_audio_activate ); - GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, 1, - on_popup_audio_activate ); - - /* sub picture menus */ - - /* find spu root menu */ - p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_window ), "menubar_subpictures" ) ); - - p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_popup ), "popup_subpictures" ) ); - - GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, 2, - on_menubar_subpictures_activate ); - GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, 2, - on_popup_subpictures_activate ); + if( p_intf->p_sys->i_part != + p_intf->p_input->stream.p_selected_area->i_part ) + { + p_intf->p_sys->b_chapter_update = 1; + GtkSetupMenus( p_intf ); + } - /* everything is ready */ - p_intf->p_sys->b_menus_update = 0; } - - /* Manage the slider */ - if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL - && p_intf->p_sys->b_scale_isfree ) + else if( !p_intf->b_die ) { - GtkWidget *p_scale; - GtkAdjustment *p_adj; - - p_scale = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( - p_intf->p_sys->p_window ), "hscale" ) ); - p_adj = gtk_range_get_adjustment ( GTK_RANGE( p_scale ) ); - - /* Update the value */ - p_adj->value = ( 100. * - p_intf->p_input->stream.p_selected_area->i_tell ) / - p_intf->p_input->stream.p_selected_area->i_size; - - /* Gtv does it this way. Why not. */ - gtk_range_set_adjustment ( GTK_RANGE( p_scale ), p_adj ); - gtk_range_slider_update ( GTK_RANGE( p_scale ) ); - gtk_range_clear_background ( GTK_RANGE( p_scale ) ); - gtk_range_draw_background ( GTK_RANGE( p_scale ) ); + GtkModeManage( p_intf ); } - /* Manage core vlc functions through the callback */ p_intf->pf_manage( p_intf ); if( p_intf->b_die ) { - /* Make sure we won't be called again */ - gtk_timeout_remove( p_intf->p_sys->i_timeout ); - - vlc_mutex_unlock( &p_intf->p_sys->change_lock ); + vlc_mutex_unlock( &p_intf->change_lock ); /* Prepare to die, young Skywalker */ gtk_main_quit(); + + /* Just in case */ return( FALSE ); } - vlc_mutex_unlock( &p_intf->p_sys->change_lock ); + vlc_mutex_unlock( &p_intf->change_lock ); return( TRUE ); -} - -/***************************************************************************** - * GtkMenuRadioItem: give a menu item adapted to language/title selection, - * ie the menu item is a radio button. - *****************************************************************************/ -static GtkWidget * GtkMenuRadioItem( GtkWidget * p_menu, - GSList ** p_button_group, - gint b_active, - char * psz_name ) -{ - GtkWidget * p_item; - -#if 0 - GtkWidget * p_button; - - /* create button */ - p_button = - gtk_radio_button_new_with_label( *p_button_group, psz_name ); - - /* add button to group */ - *p_button_group = - gtk_radio_button_group( GTK_RADIO_BUTTON( p_button ) ); - - /* prepare button for display */ - gtk_widget_show( p_button ); - - /* create menu item to store button */ - p_item = gtk_menu_item_new(); - - /* put button inside item */ - gtk_container_add( GTK_CONTAINER( p_item ), p_button ); - - /* add item to menu */ - gtk_menu_append( GTK_MENU( p_menu ), p_item ); - - gtk_signal_connect( GTK_OBJECT( p_item ), "activate", - GTK_SIGNAL_FUNC( on_audio_toggle ), - NULL ); - - - /* prepare item for display */ - gtk_widget_show( p_item ); - - /* is it the selected item ? */ - if( b_active ) - { - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( p_button ), TRUE ); - } -#else - p_item = gtk_menu_item_new_with_label( psz_name ); - gtk_menu_append( GTK_MENU( p_menu ), p_item ); - gtk_widget_show( p_item ); -#endif - - return p_item; -} - -/***************************************************************************** - * GtkLanguageMenus: update interactive menus of the interface - ***************************************************************************** - * Sets up menus with information from input: - * -languages - * -sub-pictures - * Warning: since this function is designed to be called by management - * function, the interface lock has to be taken - *****************************************************************************/ -static gint GtkLanguageMenus( gpointer p_data, - GtkWidget * p_root, - es_descriptor_t * p_es, - gint i_type, - void(*pf_activate )( GtkMenuItem *, gpointer ) ) -{ - intf_thread_t * p_intf; - GtkWidget * p_menu; - GtkWidget * p_separator; - GtkWidget * p_item; - GSList * p_button_group; - char * psz_name; - gint b_active; - gint b_audio; - gint b_spu; - gint i; - - - - /* cast */ - p_intf = (intf_thread_t *)p_data; - - vlc_mutex_lock( &p_intf->p_input->stream.stream_lock ); - - b_audio = ( i_type == 1 ); - p_button_group = NULL; - - /* menu container for audio */ - p_menu = gtk_menu_new(); - - /* create a set of language buttons and append them to the container */ - b_active = ( p_es == NULL ) ? 1 : 0; - psz_name = "Off"; - - p_item = GtkMenuRadioItem( p_menu, &p_button_group, b_active, psz_name ); - - /* setup signal hanling */ - gtk_signal_connect( GTK_OBJECT( p_item ), "activate", - GTK_SIGNAL_FUNC ( pf_activate ), NULL ); - - p_separator = gtk_menu_item_new(); - gtk_widget_show( p_separator ); - gtk_menu_append( GTK_MENU( p_menu ), p_separator ); - gtk_widget_set_sensitive( p_separator, FALSE ); - - for( i = 0 ; i < p_intf->p_input->stream.i_es_number ; i++ ) - { - - b_audio = ( i_type == 1 ) && p_intf->p_input->stream.pp_es[i]->b_audio; - b_spu = ( i_type == 2 ) && p_intf->p_input->stream.pp_es[i]->b_spu; - - if( b_audio || b_spu ) - { - b_active = ( p_es == p_intf->p_input->stream.pp_es[i] ) ? 1 : 0; - psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc; - - p_item = GtkMenuRadioItem( p_menu, &p_button_group, - b_active, psz_name ); - - /* setup signal hanling */ - gtk_signal_connect( GTK_OBJECT( p_item ), "activate", - GTK_SIGNAL_FUNC( pf_activate ), - (gpointer)( p_intf->p_input->stream.pp_es[i] ) ); - - } - } - - /* link the new menu to the menubar item */ - gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu ); - - /* be sure that menu is sensitive */ - gtk_widget_set_sensitive( p_root, TRUE ); - - vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock ); - - return TRUE; -} - -/***************************************************************************** - * GtkChapterMenu: generate chapter menu for current title - *****************************************************************************/ -static gint GtkChapterMenu( gpointer p_data, GtkWidget * p_chapter, - void(*pf_activate )( GtkMenuItem *, gpointer ) ) -{ - intf_thread_t * p_intf; - char psz_name[10]; - GtkWidget * p_chapter_menu; - GtkWidget * p_item; - GSList * p_chapter_button_group; - gint i_title; - gint i_chapter; - gint b_active; - - /* cast */ - p_intf = (intf_thread_t*)p_data; - - i_title = p_intf->p_input->stream.p_selected_area->i_id; - p_chapter_menu = gtk_menu_new(); - - for( i_chapter = 0; - i_chapter < p_intf->p_input->stream.pp_areas[i_title]->i_part_nb ; - i_chapter++ ) - { - b_active = ( p_intf->p_input->stream.pp_areas[i_title]->i_part - == i_chapter + 1 ) ? 1 : 0; - - sprintf( psz_name, "Chapter %d", i_chapter + 1 ); - - p_item = GtkMenuRadioItem( p_chapter_menu, &p_chapter_button_group, - b_active, psz_name ); - /* setup signal hanling */ - gtk_signal_connect( GTK_OBJECT( p_item ), - "activate", - GTK_SIGNAL_FUNC( pf_activate ), - (gpointer)(i_chapter + 1) ); - } - - /* link the new menu to the title menu item */ - gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter ), - p_chapter_menu ); - - /* be sure that chapter menu is sensitive */ - gtk_widget_set_sensitive( p_chapter, TRUE ); - - return TRUE; -} - -/***************************************************************************** - * GtkTitleMenu: sets menus for titles and chapters selection - ***************************************************************************** - * Generates two type of menus: - * -simple list of titles - * -cascaded lists of chapters for each title - *****************************************************************************/ -static gint GtkTitleMenu( gpointer p_data, - GtkWidget * p_navigation, - void(*pf_activate )( GtkMenuItem *, gpointer ) ) -{ - intf_thread_t * p_intf; - char psz_name[10]; - GtkWidget * p_title_menu; - GtkWidget * p_title_item; - GtkWidget * p_chapter_menu; - GtkWidget * p_item; - GSList * p_title_button_group; - GSList * p_chapter_button_group; - gint i_title; - gint i_chapter; - gint b_active; - - /* cast */ - p_intf = (intf_thread_t*)p_data; - - p_title_menu = gtk_menu_new(); - p_title_button_group = NULL; - p_chapter_button_group = NULL; - - /* loop on titles */ - for( i_title = 1 ; - i_title < p_intf->p_input->stream.i_area_nb ; - i_title++ ) - { - b_active = ( p_intf->p_input->stream.pp_areas[i_title] == - p_intf->p_input->stream.p_selected_area ) ? 1 : 0; - sprintf( psz_name, "Title %d", i_title ); - - p_title_item = GtkMenuRadioItem( p_title_menu, &p_title_button_group, - b_active, psz_name ); - - if( pf_activate == on_menubar_title_activate ) - { - /* setup signal hanling */ - gtk_signal_connect( GTK_OBJECT( p_title_item ), - "activate", - GTK_SIGNAL_FUNC( pf_activate ), - (gpointer)(p_intf->p_input->stream.pp_areas[i_title]) ); - } - else - { - p_chapter_menu = gtk_menu_new(); - - for( i_chapter = 0; - i_chapter < - p_intf->p_input->stream.pp_areas[i_title]->i_part_nb ; - i_chapter++ ) - { - b_active = ( p_intf->p_input->stream.pp_areas[i_title]->i_part - == i_chapter + 1 ) ? 1 : 0; - - sprintf( psz_name, "Chapter %d", i_chapter + 1 ); - - p_item = GtkMenuRadioItem( p_chapter_menu, - &p_chapter_button_group, - b_active, psz_name ); - - /* setup signal hanling */ - gtk_signal_connect( GTK_OBJECT( p_item ), - "activate", - GTK_SIGNAL_FUNC( pf_activate ), - (gpointer)( ( i_title * 100 ) + ( i_chapter + 1) ) ); - } - - /* link the new menu to the title menu item */ - gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ), - p_chapter_menu ); - } - - /* be sure that chapter menu is sensitive */ - gtk_widget_set_sensitive( p_title_menu, TRUE ); - - } - - /* link the new menu to the menubar audio item */ - gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu ); - - /* be sure that audio menu is sensitive */ - gtk_widget_set_sensitive( p_navigation, TRUE ); - - return TRUE; +#undef p_intf }