* gtk.c : Gtk+ plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: gtk.c,v 1.1 2002/08/04 17:23:43 sam Exp $
+ * $Id: gtk.c,v 1.16 2003/02/20 01:52:46 sigmunau Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
static void Close ( vlc_object_t * );
static void Run ( intf_thread_t * );
-static gint Manage ( gpointer );
-
-/*****************************************************************************
- * Local variables (mutex-protected).
- *****************************************************************************/
-static void ** pp_global_data = NULL;
+static int Manage ( intf_thread_t * );
/*****************************************************************************
* Module descriptor
#else
int i = getenv( "DISPLAY" ) == NULL ? 10 : 90;
#endif
- pp_global_data = p_module->p_vlc->pp_global_data;
-
- add_category_hint( N_("Miscellaneous"), NULL );
- add_bool( "gtk-tooltips", 1, GtkHideTooltips,
- TOOLTIPS_TEXT, TOOLTIPS_LONGTEXT );
+ add_category_hint( N_("Gtk+"), NULL, VLC_FALSE );
+ add_bool( "gtk-tooltips", 1, E_(GtkHideTooltips),
+ TOOLTIPS_TEXT, TOOLTIPS_LONGTEXT, VLC_FALSE );
add_integer( "gtk-prefs-maxh", 480, NULL,
- PREFS_MAXH_TEXT, PREFS_MAXH_LONGTEXT );
+ PREFS_MAXH_TEXT, PREFS_MAXH_LONGTEXT, VLC_TRUE );
set_description( _("Gtk+ interface module") );
set_capability( "interface", i );
set_callbacks( Open, Close );
+ add_shortcut( "gtk" );
set_program( "gvlc" );
vlc_module_end();
-/*****************************************************************************
- * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit
- *****************************************************************************
- * gtk_init() makes several calls to g_atexit() which calls atexit() to
- * register tidying callbacks to be called at program exit. Since the Gtk+
- * plugin is likely to be unloaded at program exit, we have to export this
- * symbol to intercept the g_atexit() calls. Talk about crude hack.
- *****************************************************************************/
-void g_atexit( GVoidFunc func )
-{
- intf_thread_t *p_intf;
-
- int i_dummy;
-
- if( pp_global_data == NULL )
- {
- atexit( func );
- return;
- }
-
- p_intf = (intf_thread_t *)*pp_global_data;
- if( p_intf == NULL )
- {
- return;
- }
-
- for( i_dummy = 0;
- i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
- i_dummy++ )
- {
- ;
- }
-
- if( i_dummy >= MAX_ATEXIT - 1 )
- {
- msg_Err( p_intf, "too many atexit() callbacks to register" );
- return;
- }
-
- p_intf->p_sys->pf_callback[i_dummy] = func;
- p_intf->p_sys->pf_callback[i_dummy + 1] = NULL;
-}
-
/*****************************************************************************
* Open: initialize and create window
*****************************************************************************/
if( p_intf->p_sys == NULL )
{
msg_Err( p_intf, "out of memory" );
- return( 1 );
+ return VLC_ENOMEM;
+ }
+
+#ifdef NEED_GTK_MAIN
+ p_intf->p_sys->p_gtk_main = module_Need( p_this, "gtk_main", "gtk" );
+ if( p_intf->p_sys->p_gtk_main == NULL )
+ {
+ free( p_intf->p_sys );
+ return VLC_ENOMOD;
}
+#endif
p_intf->pf_run = Run;
p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
/* Initialize Gtk+ thread */
- p_intf->p_sys->b_playing = 0;
- p_intf->p_sys->b_popup_changed = 0;
- p_intf->p_sys->b_window_changed = 0;
- p_intf->p_sys->b_playlist_changed = 0;
+ p_intf->p_sys->b_playing = VLC_FALSE;
+ p_intf->p_sys->b_deinterlace_update = VLC_FALSE;
+
+ p_intf->p_sys->b_aout_update = VLC_FALSE;
+ p_intf->p_sys->b_vout_update = VLC_FALSE;
+
+ p_intf->p_sys->b_popup_changed = VLC_FALSE;
+ p_intf->p_sys->b_window_changed = VLC_FALSE;
+ p_intf->p_sys->b_playlist_changed = VLC_FALSE;
+ p_intf->p_sys->b_program_update = VLC_FALSE;
+ p_intf->p_sys->b_title_update = VLC_FALSE;
+ p_intf->p_sys->b_chapter_update = VLC_FALSE;
+ p_intf->p_sys->b_spu_update = VLC_FALSE;
+ p_intf->p_sys->b_audio_update = VLC_FALSE;
p_intf->p_sys->p_input = NULL;
p_intf->p_sys->i_playing = -1;
- p_intf->p_sys->b_slider_free = 1;
-
- p_intf->p_sys->pf_callback[0] = NULL;
+ p_intf->p_sys->b_slider_free = VLC_TRUE;
p_intf->p_sys->i_part = 0;
+ p_intf->p_sys->b_mute = VLC_FALSE;
- return( 0 );
+ return VLC_SUCCESS;
}
/*****************************************************************************
msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
+#ifdef NEED_GTK_MAIN
+ module_Unneed( p_intf, p_intf->p_sys->p_gtk_main );
+#endif
+
/* Destroy structure */
free( p_intf->p_sys );
}
*****************************************************************************
* this part of the interface is in a separate thread so that we can call
* gtk_main() from within it without annoying the rest of the program.
- * XXX: the approach may look kludgy, and probably is, but I could not find
- * a better way to dynamically load a Gtk+ interface at runtime.
*****************************************************************************/
static void 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;
- int i_dummy;
-
/* The data types we are allowed to receive */
static GtkTargetEntry target_table[] =
{
{ "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST },
{ "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN }
};
+ char *psz_sout;
+ GString * p_target;
- /* Initialize Gtk+ */
+#ifdef NEED_GTK_MAIN
+ gdk_threads_enter();
+#else
+ /* 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;
+ int i_dummy;
- /* gtk_init will register stuff with g_atexit, so we need to take
- * the global lock if we want to be able to intercept the calls */
- vlc_mutex_lock( p_intf->p_vlc->p_global_lock );
- *p_intf->p_vlc->pp_global_data = p_intf;
gtk_init( &i_args, &pp_args );
- vlc_mutex_unlock( p_intf->p_vlc->p_global_lock );
+#endif
/* Create some useful widgets that will certainly be used */
p_intf->p_sys->p_window = create_intf_window();
p_intf->p_sys->p_playwin = create_intf_playlist();
p_intf->p_sys->p_messages = create_intf_messages();
p_intf->p_sys->p_tooltips = gtk_tooltips_new();
+ p_intf->p_sys->p_sout = create_intf_sout();
/* Set the title of the main window */
gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
/* Accept file drops on the main window */
gtk_drag_dest_set( GTK_WIDGET( p_intf->p_sys->p_window ),
GTK_DEST_DEFAULT_ALL, target_table,
- 1, GDK_ACTION_COPY );
+ DROP_ACCEPT_END, GDK_ACTION_COPY );
/* Accept file drops on the playlist window */
gtk_drag_dest_set( GTK_WIDGET( lookup_widget( p_intf->p_sys->p_playwin,
"playlist_clist") ),
GTK_DEST_DEFAULT_ALL, target_table,
- 1, GDK_ACTION_COPY );
+ DROP_ACCEPT_END, GDK_ACTION_COPY );
/* Get the slider object */
p_intf->p_sys->p_slider_frame = GTK_FRAME( gtk_object_get_data(
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 );
+ GTK_SIGNAL_FUNC( E_(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;
gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup),
"p_intf", p_intf );
+ gtk_object_set_data( GTK_OBJECT( gtk_object_get_data(
+ GTK_OBJECT(p_intf->p_sys->p_popup),
+ "popup_audio" ) ), "p_intf", p_intf );
+ gtk_object_set_data( GTK_OBJECT( gtk_object_get_data(
+ GTK_OBJECT(p_intf->p_sys->p_popup),
+ "popup_video" ) ), "p_intf", p_intf );
gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_playwin ),
"p_intf", p_intf );
gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_adj),
"p_intf", p_intf );
+ gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_sout ),
+ "p_intf", p_intf );
+
+ psz_sout = config_GetPsz( p_intf, "sout" );
+ p_target = g_string_new( psz_sout ? psz_sout : "" );
+ if( psz_sout ) free( psz_sout );
+
+ gtk_entry_set_text( gtk_object_get_data( GTK_OBJECT( p_intf->p_sys->p_sout ), "sout_entry_target" ), p_target->str );
+ g_string_free( p_target, TRUE );
+
+ /* FIXME it's to be sure that only file entry is selected */
+ gtk_toggle_button_set_active( gtk_object_get_data( GTK_OBJECT( p_intf->p_sys->p_sout ),
+ "sout_access_udp" ), TRUE );
+
+ gtk_toggle_button_set_active( gtk_object_get_data( GTK_OBJECT( p_intf->p_sys->p_sout ),
+ "sout_access_file" ), TRUE );
/* Show the control window */
gtk_widget_show( p_intf->p_sys->p_window );
+#ifdef NEED_GTK_MAIN
+ while( !p_intf->b_die )
+ {
+ Manage( p_intf );
+
+ /* Sleep to avoid using all CPU - since some interfaces need to
+ * access keyboard events, a 100ms delay is a good compromise */
+ gdk_threads_leave();
+ msleep( INTF_IDLE_SLEEP );
+ gdk_threads_enter();
+ }
+#else
/* Sleep to avoid using all CPU - since some interfaces needs to access
* keyboard events, a 100ms delay is a good compromise */
- i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, Manage, p_intf );
-
+ i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, (GtkFunction)Manage,
+ p_intf );
/* Enter Gtk mode */
gtk_main();
-
/* Remove the timeout */
gtk_timeout_remove( i_dummy );
+#endif
/* Destroy the Tooltips structure */
gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_tooltips) );
+ gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_messages) );
+ gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_playwin) );
+ gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_popup) );
+ gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_window) );
- /* Launch stored callbacks */
- for( i_dummy = 0;
- i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
- i_dummy++ )
- {
- p_intf->p_sys->pf_callback[i_dummy]();
- }
+#ifdef NEED_GTK_MAIN
+ gdk_threads_leave();
+#endif
}
/* following functions are local */
* In this function, called approx. 10 times a second, we check what the
* main program wanted to tell us.
*****************************************************************************/
-static gint Manage( gpointer p_data )
+static int Manage( intf_thread_t *p_intf )
{
-#define p_intf ((intf_thread_t *)p_data)
int i_start, i_stop;
vlc_mutex_lock( &p_intf->change_lock );
}
/* Update the playlist */
- GtkPlayListManage( p_data );
+ GtkPlayListManage( p_intf );
/* Update the input */
if( p_intf->p_sys->p_input == NULL )
if( p_intf->p_sys->p_input )
{
- input_thread_t *p_input = p_intf->p_sys->p_input;
+ input_thread_t *p_input = p_intf->p_sys->p_input;
+ aout_instance_t *p_aout = NULL;
+ vout_thread_t *p_vout = NULL;
+ vlc_bool_t b_need_menus = VLC_FALSE;
vlc_mutex_lock( &p_input->stream.stream_lock );
/* New input or stream map change */
if( p_input->stream.b_changed )
{
- GtkModeManage( p_intf );
+ E_(GtkModeManage)( p_intf );
GtkSetupMenus( p_intf );
p_intf->p_sys->b_playing = 1;
}
"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 )
+ * finished dragging the slider.
+ * Beware, the hack below is needed by the dvdplay plugin! */
+ else if( p_intf->p_sys->b_slider_free
+ /* hack -> */ && (p_intf->p_sys->f_adj_oldvalue <= 100.) )
{
off_t i_seek = ( newvalue * p_area->i_size ) / 100;
p_input->stream.p_selected_area->i_part )
{
p_intf->p_sys->b_chapter_update = 1;
+ b_need_menus = VLC_TRUE;
+ }
+
+ /* Does the audio output require to update the menus ? */
+ p_aout = (aout_instance_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,
+ FIND_ANYWHERE );
+ if( p_aout != NULL )
+ {
+ vlc_value_t val;
+ if( var_Get( (vlc_object_t *)p_aout, "intf-change", &val ) >= 0
+ && val.b_bool )
+ {
+ p_intf->p_sys->b_aout_update = 1;
+ b_need_menus = 1;
+ }
+
+ vlc_object_release( (vlc_object_t *)p_aout );
+ }
+
+ /* Does the video output require to update the menus ? */
+ p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
+ FIND_ANYWHERE );
+ if( p_vout != NULL )
+ {
+ vlc_value_t val;
+ if( var_Get( (vlc_object_t *)p_vout, "intf-change", &val ) >= 0
+ && val.b_bool )
+ {
+ p_intf->p_sys->b_vout_update = 1;
+ b_need_menus = 1;
+ }
+
+ vlc_object_release( (vlc_object_t *)p_vout );
+ }
+ if( b_need_menus )
+ {
GtkSetupMenus( p_intf );
}
}
}
else if( p_intf->p_sys->b_playing && !p_intf->b_die )
{
- GtkModeManage( p_intf );
+ E_(GtkModeManage)( p_intf );
p_intf->p_sys->b_playing = 0;
}
+#ifndef NEED_GTK_MAIN
if( p_intf->b_die )
{
vlc_mutex_unlock( &p_intf->change_lock );
/* Prepare to die, young Skywalker */
gtk_main_quit();
- /* Just in case */
- return( FALSE );
+ return FALSE;
}
+#endif
vlc_mutex_unlock( &p_intf->change_lock );
- return( TRUE );
-
-#undef p_intf
+ return TRUE;
}