]> git.sesse.net Git - vlc/blobdiff - modules/gui/gtk/gtk.c
* include/configuration.h: added a new flag to the configuration stucture to
[vlc] / modules / gui / gtk / gtk.c
index 7309aa3c49f4003b968a9972092d107b8e667fc1..3e141baea88ebdd7502ed7b8c84f25f133158d22 100644 (file)
@@ -2,7 +2,7 @@
  * 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>
  *
@@ -10,7 +10,7 @@
  * 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
@@ -49,12 +49,7 @@ static int  Open         ( vlc_object_t * );
 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
@@ -73,63 +68,19 @@ vlc_module_begin();
 #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
  *****************************************************************************/
@@ -142,28 +93,46 @@ static int Open( vlc_object_t *p_this )
     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;
 }
 
 /*****************************************************************************
@@ -180,6 +149,10 @@ static void Close( vlc_object_t *p_this )
 
     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 );
 }
@@ -189,18 +162,9 @@ static void Close( vlc_object_t *p_this )
  *****************************************************************************
  * 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[] =
     {
@@ -208,15 +172,21 @@ static void Run( intf_thread_t *p_intf )
         { "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();
@@ -224,6 +194,7 @@ static void Run( intf_thread_t *p_intf )
     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),
@@ -232,13 +203,13 @@ static void Run( intf_thread_t *p_intf )
     /* 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(
@@ -263,10 +234,12 @@ static void Run( intf_thread_t *p_intf )
     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;
@@ -285,6 +258,12 @@ static void 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( 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 );
@@ -294,30 +273,58 @@ static void Run( intf_thread_t *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 */
@@ -328,9 +335,8 @@ static void 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 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 );
@@ -394,7 +400,7 @@ static gint Manage( gpointer p_data )
     }
 
     /* Update the playlist */
-    GtkPlayListManage( p_data );
+    GtkPlayListManage( p_intf );
 
     /* Update the input */
     if( p_intf->p_sys->p_input == NULL )
@@ -410,7 +416,10 @@ static gint Manage( gpointer p_data )
 
     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 );
 
@@ -419,7 +428,7 @@ static gint Manage( gpointer p_data )
             /* 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;
             }
@@ -443,8 +452,10 @@ static gint Manage( gpointer p_data )
                                              "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;
 
@@ -463,6 +474,42 @@ static gint Manage( gpointer p_data )
                 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 );
             }
         }
@@ -471,10 +518,11 @@ static gint Manage( gpointer p_data )
     }
     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 );
@@ -482,13 +530,11 @@ static gint Manage( gpointer p_data )
         /* 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;
 }