pda.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:25k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * pda.c : PDA Gtk2 plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: pda.c 7945 2004-06-07 21:26:35Z fenrir $
  6.  *
  7.  * Authors: Jean-Paul Saman <jpsaman@wxs.nl>
  8.  *          Marc Ariberti <marcari@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                                      /* malloc(), free() */
  28. #include <errno.h>                                                 /* ENOMEM */
  29. #include <string.h>                                            /* strerror() */
  30. #include <stdio.h>
  31. #include <vlc/vlc.h>
  32. #include <vlc/intf.h>
  33. #include <gtk/gtk.h>
  34. #include "pda_callbacks.h"
  35. #include "pda_interface.h"
  36. #include "pda_support.h"
  37. #include "pda.h"
  38. /*****************************************************************************
  39.  * Local prototypes.
  40.  *****************************************************************************/
  41. static int  Open         ( vlc_object_t * );
  42. static void Close        ( vlc_object_t * );
  43. static void Run          ( intf_thread_t * );
  44. void GtkAutoPlayFile     ( vlc_object_t * );
  45. static int Manage        ( intf_thread_t *p_intf );
  46. void E_(GtkDisplayDate)  ( GtkAdjustment *p_adj, gpointer userdata );
  47. gint E_(GtkModeManage)   ( intf_thread_t * p_intf );
  48. /*****************************************************************************
  49.  * Module descriptor
  50.  *****************************************************************************/
  51. #define AUTOPLAYFILE_TEXT  N_("Autoplay selected file")
  52. #define AUTOPLAYFILE_LONGTEXT N_("Automatically play a file when selected in the "
  53.         "file selection list")
  54. /*****************************************************************************
  55.  * Module descriptor
  56.  *****************************************************************************/
  57. vlc_module_begin();
  58.     set_description( N_("PDA Linux Gtk2+ interface") );
  59. //    add_bool( "pda-autoplayfile", 1, GtkAutoPlayFile, AUTOPLAYFILE_TEXT, AUTOPLAYFILE_LONGTEXT, VLC_TRUE );
  60.     set_capability( "interface", 70 );
  61.     set_callbacks( Open, Close );
  62.     add_shortcut( "pda" );
  63. vlc_module_end();
  64. /*****************************************************************************
  65.  * Open: initialize and create window
  66.  *****************************************************************************/
  67. static int Open( vlc_object_t *p_this )
  68. {
  69.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  70.     /* Allocate instance and initialize some members */
  71.     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  72.     if( p_intf->p_sys == NULL )
  73.     {
  74.         msg_Err( p_intf, "out of memory" );
  75.         return VLC_ENOMEM;
  76.     }
  77. #ifdef NEED_GTK2_MAIN
  78.     msg_Dbg( p_intf, "Using gui-helper" );
  79.     p_intf->p_sys->p_gtk_main =
  80.         module_Need( p_this, "gui-helper", "gtk2", VLC_TRUE );
  81.     if( p_intf->p_sys->p_gtk_main == NULL )
  82.     {
  83.         free( p_intf->p_sys );
  84.         return VLC_ENOMOD;
  85.     }
  86. #endif
  87.     /* Initialize Gtk+ thread */
  88.     p_intf->p_sys->p_input = NULL;
  89.     p_intf->p_sys->b_autoplayfile = 1;
  90.     p_intf->p_sys->b_playing = 0;
  91.     p_intf->p_sys->b_slider_free = 1;
  92.     p_intf->pf_run = Run;
  93.     return VLC_SUCCESS;
  94. }
  95. /*****************************************************************************
  96.  * Close: destroy interface window
  97.  *****************************************************************************/
  98. static void Close( vlc_object_t *p_this )
  99. {
  100.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  101.     if( p_intf->p_sys->p_input )
  102.     {
  103.         vlc_object_release( p_intf->p_sys->p_input );
  104.     }
  105. #ifdef NEED_GTK2_MAIN
  106.     msg_Dbg( p_intf, "Releasing gui-helper" );
  107.     module_Unneed( p_intf, p_intf->p_sys->p_gtk_main );
  108. #endif
  109.     /* Destroy structure */
  110.     free( p_intf->p_sys );
  111. }
  112. /*****************************************************************************
  113.  * Run: Gtk+ thread
  114.  *****************************************************************************
  115.  * this part of the interface is in a separate thread so that we can call
  116.  * gtk_main() from within it without annoying the rest of the program.
  117.  *****************************************************************************/
  118. static void Run( intf_thread_t *p_intf )
  119. {
  120. #ifndef NEED_GTK2_MAIN
  121.     /* gtk_init needs to know the command line. We don't care, so we
  122.      * give it an empty one */
  123.     char  *p_args[] = { "", NULL };
  124.     char **pp_args  = p_args;
  125.     int    i_args   = 1;
  126.     int    i_dummy;
  127. #endif
  128.     playlist_t        *p_playlist;
  129.     GtkCellRenderer   *p_renderer = NULL;
  130.     GtkTreeViewColumn *p_column   = NULL;
  131.     GtkListStore      *p_filelist = NULL;
  132.     GtkListStore      *p_playlist_store = NULL;
  133. #ifndef NEED_GTK2_MAIN
  134.     gtk_set_locale ();
  135.     msg_Dbg( p_intf, "Starting pda GTK2+ interface" );
  136.     gtk_init( &i_args, &pp_args );
  137. #else
  138.     /* Initialize Gtk+ */
  139.     msg_Dbg( p_intf, "Starting pda GTK2+ interface thread" );
  140.     gdk_threads_enter();
  141. #endif
  142.     /* Create some useful widgets that will certainly be used */
  143. /* FIXME: magic path */
  144.     add_pixmap_directory("share");
  145.     add_pixmap_directory("/usr/share/vlc");
  146.     /* Path for pixmaps under linupy 1.4 */
  147.     add_pixmap_directory("/usr/local/share/pixmaps/vlc");
  148.     /* Path for pixmaps under linupy 2.0 */
  149.     add_pixmap_directory("/usr/share/pixmaps/vlc");
  150.     p_intf->p_sys->p_window = create_pda();
  151.     if (p_intf->p_sys->p_window == NULL)
  152.     {
  153.         msg_Err( p_intf, "unable to create pda interface" );
  154.     }
  155.     /* Store p_intf to keep an eye on it */
  156.     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
  157.                          "p_intf", p_intf );
  158.     /* Set the title of the main window */
  159.     gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
  160.                           VOUT_TITLE " (PDA Linux interface)");
  161.     /* Get the notebook object */
  162.     p_intf->p_sys->p_notebook = GTK_NOTEBOOK( gtk_object_get_data(
  163.         GTK_OBJECT( p_intf->p_sys->p_window ), "notebook" ) );
  164.     /* Get the slider object */
  165.     p_intf->p_sys->p_slider = (GtkHScale*) lookup_widget( p_intf->p_sys->p_window, "timeSlider" );
  166.     p_intf->p_sys->p_slider_label = (GtkLabel*) lookup_widget( p_intf->p_sys->p_window, "timeLabel" );
  167.     if (p_intf->p_sys->p_slider == NULL)
  168.         msg_Err( p_intf, "Time slider widget not found." );
  169.     if (p_intf->p_sys->p_slider_label == NULL)
  170.         msg_Err( p_intf, "Time label widget not found." );
  171.     /* Connect the date display to the slider */
  172.     p_intf->p_sys->p_adj = gtk_range_get_adjustment( GTK_RANGE(p_intf->p_sys->p_slider) );
  173.     if (p_intf->p_sys->p_adj == NULL)
  174.         msg_Err( p_intf, "Adjustment range not found." );
  175.     g_signal_connect( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed",
  176.                          G_CALLBACK( E_(GtkDisplayDate) ), p_intf );
  177.     p_intf->p_sys->f_adj_oldvalue = 0;
  178.     p_intf->p_sys->i_adj_oldvalue = 0;
  179.     /* BEGIN OF FILEVIEW GTK_TREE_VIEW */
  180.     p_intf->p_sys->p_tvfile = NULL;
  181.     p_intf->p_sys->p_tvfile = (GtkTreeView *) lookup_widget( p_intf->p_sys->p_window,
  182.                                                              "tvFileList");
  183.     if (NULL == p_intf->p_sys->p_tvfile)
  184.        msg_Err(p_intf, "Error obtaining pointer to File List");
  185.     /* Insert columns 0 */
  186.     p_renderer = gtk_cell_renderer_text_new ();
  187.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvfile, 0, (gchar *) N_("Filename"), p_renderer, NULL);
  188.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvfile, 0 );
  189.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 0 );
  190.     gtk_tree_view_column_set_sort_column_id(p_column, 0);
  191.     /* Insert columns 1 */
  192.     p_renderer = gtk_cell_renderer_text_new ();
  193.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvfile, 1, (gchar *) N_("Permissions"), p_renderer, NULL);
  194.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvfile, 1 );
  195.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 1 );
  196.     gtk_tree_view_column_set_sort_column_id(p_column, 1);
  197.     /* Insert columns 2 */
  198.     p_renderer = gtk_cell_renderer_text_new ();
  199.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvfile, 2, (gchar *) N_("Size"), p_renderer, NULL);
  200.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvfile, 2 );
  201.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 2 );
  202.     gtk_tree_view_column_set_sort_column_id(p_column, 2);
  203.     /* Insert columns 3 */
  204.     p_renderer = gtk_cell_renderer_text_new ();
  205.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvfile, 3, (gchar *) N_("Owner"), p_renderer, NULL);
  206.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvfile, 3 );
  207.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 3 );
  208.     gtk_tree_view_column_set_sort_column_id(p_column, 3);
  209.     /* Insert columns 4 */
  210.     p_renderer = gtk_cell_renderer_text_new ();
  211.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvfile, 4, (gchar *) N_("Group"), p_renderer, NULL);
  212.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvfile, 4 );
  213.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 4 );
  214.     gtk_tree_view_column_set_sort_column_id(p_column, 4);
  215.     /* Get new directory listing */
  216.     p_filelist = gtk_list_store_new (5,
  217.                 G_TYPE_STRING, /* Filename */
  218.                 G_TYPE_STRING, /* permissions */
  219.                 G_TYPE_UINT64, /* File size */
  220.                 G_TYPE_STRING, /* Owner */
  221.                 G_TYPE_STRING);/* Group */
  222.     ReadDirectory(p_intf, p_filelist, ".");
  223.     gtk_tree_view_set_model(GTK_TREE_VIEW(p_intf->p_sys->p_tvfile), GTK_TREE_MODEL(p_filelist));
  224.     g_object_unref(p_filelist);     /* Model will be released by GtkTreeView */
  225.     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(p_intf->p_sys->p_tvfile)),GTK_SELECTION_MULTIPLE);
  226.     /* Column properties */
  227.     gtk_tree_view_set_headers_visible(p_intf->p_sys->p_tvfile, TRUE);
  228.     gtk_tree_view_columns_autosize(p_intf->p_sys->p_tvfile);
  229.     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(p_intf->p_sys->p_tvfile),TRUE);
  230.     /* END OF FILEVIEW GTK_TREE_VIEW */
  231.     /* BEGIN OF PLAYLIST GTK_TREE_VIEW */
  232.     p_intf->p_sys->p_tvplaylist = NULL;
  233.     p_intf->p_sys->p_tvplaylist = (GtkTreeView *) lookup_widget( p_intf->p_sys->p_window, "tvPlaylist");
  234.     if (NULL == p_intf->p_sys->p_tvplaylist)
  235.        msg_Err(p_intf, "Error obtaining pointer to Play List");
  236.     /* Columns 1 */
  237.     p_renderer = gtk_cell_renderer_text_new ();
  238.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvplaylist, 0, (gchar *) N_("Filename"), p_renderer, NULL);
  239.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvplaylist, 0 );
  240.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 0 );
  241.     gtk_tree_view_column_set_sort_column_id(p_column, 0);
  242.     /* Column 2 */
  243.     p_renderer = gtk_cell_renderer_text_new ();
  244.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvplaylist, 1, (gchar *) N_("Time"), p_renderer, NULL);
  245.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvplaylist, 1 );
  246.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 1 );
  247.     gtk_tree_view_column_set_sort_column_id(p_column, 1);
  248. #if 0
  249.     /* Column 3 - is a hidden column used for reliable deleting items from the underlying playlist */
  250.     p_renderer = gtk_cell_renderer_text_new ();
  251.     gtk_tree_view_insert_column_with_attributes(p_intf->p_sys->p_tvplaylist, 2, (gchar *) N_("Index"), p_renderer, NULL);
  252.     p_column = gtk_tree_view_get_column(p_intf->p_sys->p_tvplaylist, 2 );
  253.     gtk_tree_view_column_add_attribute(p_column, p_renderer, "text", 2 );
  254.     gtk_tree_view_column_set_sort_column_id(p_column, 2);
  255. #endif
  256.     /* update the playlist */
  257.     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
  258.     p_playlist_store = gtk_list_store_new (3,
  259.                 G_TYPE_STRING, /* Filename */
  260.                 G_TYPE_STRING, /* Time */
  261.                 G_TYPE_UINT);  /* Hidden index */
  262.     PlaylistRebuildListStore(p_playlist_store, p_playlist);
  263.     gtk_tree_view_set_model(GTK_TREE_VIEW(p_intf->p_sys->p_tvplaylist), GTK_TREE_MODEL(p_playlist_store));
  264.     g_object_unref(p_playlist_store);
  265.     vlc_object_release(p_playlist); /* Free the playlist */
  266.     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(p_intf->p_sys->p_tvplaylist)),GTK_SELECTION_MULTIPLE);
  267.     /* Column properties */
  268.     gtk_tree_view_set_headers_visible(p_intf->p_sys->p_tvplaylist, TRUE);
  269.     gtk_tree_view_columns_autosize(p_intf->p_sys->p_tvplaylist);
  270.     gtk_tree_view_set_headers_clickable(p_intf->p_sys->p_tvplaylist, TRUE);
  271.     /* END OF PLAYLIST GTK_TREE_VIEW */
  272.     /* Hide the Preference TAB for now. */
  273.     GtkWidget *p_preference_tab = NULL;
  274.     p_preference_tab = gtk_notebook_get_nth_page(p_intf->p_sys->p_notebook,5);
  275.     if (p_preference_tab != NULL)
  276.       gtk_widget_hide(p_preference_tab);
  277.     /* Show the control window */
  278.     gtk_widget_show( p_intf->p_sys->p_window );
  279. #ifdef NEED_GTK2_MAIN
  280.     msg_Dbg( p_intf, "Manage GTK keyboard events using threads" );
  281.     while( !p_intf->b_die )
  282.     {
  283.         Manage( p_intf );
  284.         /* Sleep to avoid using all CPU - since some interfaces need to
  285.          * access keyboard events, a 100ms delay is a good compromise */
  286.         gdk_threads_leave();
  287.         if (p_intf->p_libvlc->i_cpu & CPU_CAPABILITY_FPU)
  288.             msleep( INTF_IDLE_SLEEP );
  289.         else
  290.             msleep( 1000 );
  291.         gdk_threads_enter();
  292.     }
  293. #else
  294.     msg_Dbg( p_intf, "Manage GTK keyboard events using timeouts" );
  295.     /* Sleep to avoid using all CPU - since some interfaces needs to access
  296.      * keyboard events, a 1000ms delay is a good compromise */
  297.     if (p_intf->p_libvlc->i_cpu & CPU_CAPABILITY_FPU)
  298.         i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, (GtkFunction)Manage, p_intf );
  299.     else
  300.         i_dummy = gtk_timeout_add( 1000, (GtkFunction)Manage, p_intf );
  301.     /* Enter Gtk mode */
  302.     gtk_main();
  303.     /* Remove the timeout */
  304.     gtk_timeout_remove( i_dummy );
  305. #endif
  306.     gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_window) );
  307. #ifdef NEED_GTK2_MAIN
  308.     gdk_threads_leave();
  309. #endif
  310. }
  311. /*****************************************************************************
  312.  * GtkAutoplayFile: Autoplay file depending on configuration settings
  313.  *****************************************************************************/
  314. void GtkAutoPlayFile( vlc_object_t *p_this )
  315. {
  316.     GtkWidget *cbautoplay;
  317.     intf_thread_t *p_intf;
  318.     int i_index;
  319.     vlc_list_t *p_list = vlc_list_find( p_this, VLC_OBJECT_INTF,
  320.                                         FIND_ANYWHERE );
  321.     for( i_index = 0; i_index < p_list->i_count; i_index++ )
  322.     {
  323.         p_intf = (intf_thread_t *)p_list->p_values[i_index].p_object ;
  324.         if( strcmp( MODULE_STRING, p_intf->p_module->psz_object_name ) )
  325.         {
  326.             continue;
  327.         }
  328.         cbautoplay = GTK_WIDGET( gtk_object_get_data(
  329.                             GTK_OBJECT( p_intf->p_sys->p_window ),
  330.                             "cbautoplay" ) );
  331.         if( !config_GetInt( p_this, "pda-autoplayfile" ) )
  332.         {
  333.             p_intf->p_sys->b_autoplayfile = VLC_FALSE;
  334.         }
  335.         else
  336.         {
  337.             p_intf->p_sys->b_autoplayfile = VLC_TRUE;
  338.         }
  339.         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( cbautoplay ),
  340.                                       p_intf->p_sys->b_autoplayfile );
  341.     }
  342.     vlc_list_release( p_list );
  343. }
  344. /* following functions are local */
  345. /*****************************************************************************
  346.  * Manage: manage main thread messages
  347.  *****************************************************************************
  348.  * In this function, called approx. 10 times a second, we check what the
  349.  * main program wanted to tell us.
  350.  *****************************************************************************/
  351. static int Manage( intf_thread_t *p_intf )
  352. {
  353.     GtkListStore *p_liststore;
  354.     vlc_mutex_lock( &p_intf->change_lock );
  355.     /* Update the input */
  356.     if( p_intf->p_sys->p_input == NULL )
  357.     {
  358.         p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
  359.                                                           FIND_ANYWHERE );
  360.     }
  361.     else if( p_intf->p_sys->p_input->b_dead )
  362.     {
  363.         vlc_object_release( p_intf->p_sys->p_input );
  364.         p_intf->p_sys->p_input = NULL;
  365.     }
  366.     if( p_intf->p_sys->p_input )
  367.     {
  368.         input_thread_t *p_input = p_intf->p_sys->p_input;
  369.         vlc_mutex_lock( &p_input->stream.stream_lock );
  370.         if( !p_input->b_die )
  371.         {
  372.             /* New input or stream map change */
  373.             if( p_input->stream.b_changed )
  374.             {
  375.                 playlist_t *p_playlist;
  376.                 E_(GtkModeManage)( p_intf );
  377.                 p_intf->p_sys->b_playing = 1;
  378.                 /* update playlist interface */
  379.                 p_playlist = (playlist_t *) vlc_object_find(
  380.                         p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
  381.                 if (p_playlist != NULL)
  382.                 {
  383.                     p_liststore = gtk_list_store_new (3,
  384.                                                G_TYPE_STRING,
  385.                                                G_TYPE_STRING,
  386.                                                G_TYPE_UINT);  /* Hidden index */
  387.                     PlaylistRebuildListStore(p_liststore, p_playlist);
  388.                     gtk_tree_view_set_model(p_intf->p_sys->p_tvplaylist, (GtkTreeModel*) p_liststore);
  389.                     g_object_unref(p_liststore);
  390.                     vlc_object_release( p_playlist );
  391.                 }
  392.             }
  393.             /* Manage the slider */
  394. #define p_area p_input->stream.p_selected_area
  395.             if (p_intf->p_libvlc->i_cpu & CPU_CAPABILITY_FPU)
  396.             {
  397.                 /* Manage the slider for CPU_CAPABILITY_FPU hardware */
  398.                 if( p_input->stream.b_seekable && p_intf->p_sys->b_playing )
  399.                 {
  400.                     float newvalue = p_intf->p_sys->p_adj->value;
  401.                     /* If the user hasn't touched the slider since the last time,
  402.                      * then the input can safely change it */
  403.                     if( newvalue == p_intf->p_sys->f_adj_oldvalue )
  404.                     {
  405.                         /* Update the value */
  406.                         p_intf->p_sys->p_adj->value =
  407.                         p_intf->p_sys->f_adj_oldvalue =
  408.                             ( 100. * p_area->i_tell ) / p_area->i_size;
  409.                         g_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
  410.                                                  "value_changed" );
  411.                     }
  412.                     /* Otherwise, send message to the input if the user has
  413.                      * finished dragging the slider */
  414.                     else if( p_intf->p_sys->b_slider_free )
  415.                     {
  416.                         double f_pos = (double)newvalue / 100.0;
  417.                         /* release the lock to be able to seek */
  418.                         vlc_mutex_unlock( &p_input->stream.stream_lock );
  419.                         var_SetFloat( p_input, "position", f_pos );
  420.                         vlc_mutex_lock( &p_input->stream.stream_lock );
  421.                         /* Update the old value */
  422.                         p_intf->p_sys->f_adj_oldvalue = newvalue;
  423.                     }
  424.                 }
  425.             }
  426.             else
  427.             {
  428.                 /* Manage the slider without CPU_CAPABILITY_FPU hardware */
  429.                 if( p_input->stream.b_seekable && p_intf->p_sys->b_playing )
  430.                 {
  431.                     off_t newvalue = p_intf->p_sys->p_adj->value;
  432.                     /* If the user hasn't touched the slider since the last time,
  433.                      * then the input can safely change it */
  434.                     if( newvalue == p_intf->p_sys->i_adj_oldvalue )
  435.                     {
  436.                         /* Update the value */
  437.                         p_intf->p_sys->p_adj->value =
  438.                         p_intf->p_sys->i_adj_oldvalue =
  439.                             ( 100 * p_area->i_tell ) / p_area->i_size;
  440.                         g_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
  441.                                                  "value_changed" );
  442.                     }
  443.                     /* Otherwise, send message to the input if the user has
  444.                      * finished dragging the slider */
  445.                     else if( p_intf->p_sys->b_slider_free )
  446.                     {
  447.                         double f_pos = (double)newvalue / 100.0;
  448.                         /* release the lock to be able to seek */
  449.                         vlc_mutex_unlock( &p_input->stream.stream_lock );
  450.                         var_SetFloat( p_input, "position", f_pos );
  451.                         vlc_mutex_lock( &p_input->stream.stream_lock );
  452.                         /* Update the old value */
  453.                         p_intf->p_sys->i_adj_oldvalue = newvalue;
  454.                     }
  455.                 }
  456.             }
  457. #undef p_area
  458.         }
  459.         vlc_mutex_unlock( &p_input->stream.stream_lock );
  460.     }
  461.     else if( p_intf->p_sys->b_playing && !p_intf->b_die )
  462.     {
  463.         E_(GtkModeManage)( p_intf );
  464.         p_intf->p_sys->b_playing = 0;
  465.     }
  466. #ifndef NEED_GTK2_MAIN
  467.     if( p_intf->b_die )
  468.     {
  469.         vlc_mutex_unlock( &p_intf->change_lock );
  470.         /* Prepare to die, young Skywalker */
  471.         gtk_main_quit();
  472.         return FALSE;
  473.     }
  474. #endif
  475.     vlc_mutex_unlock( &p_intf->change_lock );
  476.     return TRUE;
  477. }
  478. /*****************************************************************************
  479.  * GtkDisplayDate: display stream date
  480.  *****************************************************************************
  481.  * This function displays the current date related to the position in
  482.  * the stream. It is called whenever the slider changes its value.
  483.  * The lock has to be taken before you call the function.
  484.  *****************************************************************************/
  485. void E_(GtkDisplayDate)( GtkAdjustment *p_adj, gpointer userdata )
  486. {
  487.     intf_thread_t *p_intf;
  488.     p_intf = (intf_thread_t*) userdata;
  489.     if (p_intf == NULL)
  490.         return;
  491.     if( p_intf->p_sys->p_input )
  492.     {
  493.         char psz_time[ MSTRTIME_MAX_SIZE ];
  494.         int64_t i_seconds;
  495.         i_seconds = var_GetTime( p_intf->p_sys->p_input, "time" ) / I64C(1000000 );
  496.         secstotimestr( psz_time, i_seconds );
  497.         gtk_label_set_text( GTK_LABEL( p_intf->p_sys->p_slider_label ),
  498.                             psz_time );
  499.      }
  500. }
  501. /*****************************************************************************
  502.  * GtkModeManage: actualize the aspect of the interface whenever the input
  503.  *                changes.
  504.  *****************************************************************************
  505.  * The lock has to be taken before you call the function.
  506.  *****************************************************************************/
  507. gint E_(GtkModeManage)( intf_thread_t * p_intf )
  508. {
  509.     GtkWidget *     p_slider = NULL;
  510.     vlc_bool_t      b_control;
  511.     if ( p_intf->p_sys->p_window == NULL )
  512.         msg_Err( p_intf, "Main widget not found" );
  513.     p_slider = lookup_widget( p_intf->p_sys->p_window, "timeSlider");
  514.     if (p_slider == NULL)
  515.         msg_Err( p_intf, "Slider widget not found" );
  516.     /* controls unavailable */
  517.     b_control = 0;
  518.     /* show the box related to current input mode */
  519.     if( p_intf->p_sys->p_input )
  520.     {
  521.         /* initialize and show slider for seekable streams */
  522.         if( p_intf->p_sys->p_input->stream.b_seekable )
  523.         {
  524.             gtk_widget_show( GTK_WIDGET( p_slider ) );
  525.         }
  526.         else
  527.         {
  528.             /* hide slider */
  529.             gtk_widget_hide( GTK_WIDGET( p_slider ) );
  530.         }
  531.         /* control buttons for free pace streams */
  532.         b_control = p_intf->p_sys->p_input->stream.b_pace_control;
  533.         p_intf->p_sys->p_input->stream.b_changed = 0;
  534.         msg_Dbg( p_intf, "stream has changed, refreshing interface" );
  535.     }
  536.     /* set control items */
  537.     gtk_widget_set_sensitive( lookup_widget( p_intf->p_sys->p_window, "tbRewind"), b_control );
  538.     gtk_widget_set_sensitive( lookup_widget( p_intf->p_sys->p_window, "tbPause"), b_control );
  539.     gtk_widget_set_sensitive( lookup_widget( p_intf->p_sys->p_window, "tbForward"), b_control );
  540.     return TRUE;
  541. }