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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * gtk_preferences.c: functions to handle the preferences dialog box.
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: preferences.c 6961 2004-03-05 17:34:23Z sam $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  8.  *          Lo颿 Minier <lool@via.ecp.fr>
  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: Our main job is to build a nice interface from the modules config
  26.  *   structure. Once this is done, we need to track each change made by the
  27.  *   user to the data contained in this interface so that when/if he decides to
  28.  *   apply his changes we can quickly commit them into the modules config
  29.  *   structure. (for this last task we use a GHashTable to accumulate the
  30.  *   changes. To commit them, we then just have to circle through it )
  31.  *
  32.  *****************************************************************************/
  33. #include <sys/types.h>                                              /* off_t */
  34. #include <stdlib.h>
  35. #include <vlc/vlc.h>
  36. #include <vlc/intf.h>
  37. #ifdef MODULE_NAME_IS_gnome
  38. #   include <gnome.h>
  39. #else
  40. #   include <gtk/gtk.h>
  41. #endif
  42. #include <string.h>
  43. #include "gtk_support.h"
  44. #include "common.h"
  45. #include "preferences.h"
  46. /* local functions */
  47. static void GtkCreateConfigDialog( char *, intf_thread_t * );
  48. static void GtkConfigOk          ( GtkButton *, gpointer );
  49. static void GtkConfigApply       ( GtkButton *, gpointer );
  50. static void GtkConfigCancel      ( GtkButton *, gpointer );
  51. static void GtkConfigSave        ( GtkButton *, gpointer );
  52. static void GtkConfigDialogDestroyed ( GtkObject *, gpointer );
  53. static void GtkStringChanged     ( GtkEditable *, gpointer );
  54. static void GtkIntChanged        ( GtkEditable *, gpointer );
  55. static void GtkIntRangedChanged  ( GtkEditable *, gpointer );
  56. static void GtkFloatChanged      ( GtkEditable *, gpointer );
  57. static void GtkFloatRangedChanged      ( GtkEditable *, gpointer );
  58. static void GtkBoolChanged       ( GtkToggleButton *, gpointer );
  59. static void GtkFreeHashTable     ( GtkObject *object );
  60. static void GtkFreeHashValue     ( gpointer, gpointer, gpointer );
  61. static gboolean GtkSaveHashValue ( gpointer, gpointer, gpointer );
  62. static void GtkModuleConfigure   ( GtkButton *, gpointer );
  63. static void GtkModuleSelected    ( GtkButton *, gpointer );
  64. static void GtkModuleHighlighted ( GtkCList *, int, int, GdkEventButton *,
  65.                                    gpointer );
  66. /****************************************************************************
  67.  * Callback for menuitems: display configuration interface window
  68.  ****************************************************************************/
  69. void GtkPreferencesShow( GtkMenuItem * menuitem, gpointer user_data )
  70. {
  71.     intf_thread_t * p_intf;
  72.     p_intf = GtkGetIntf( menuitem );
  73.     GtkCreateConfigDialog( "main", p_intf );
  74. }
  75. /****************************************************************************
  76.  * GtkCreateConfigDialog: dynamically creates the configuration dialog
  77.  * box from all the configuration data provided by the selected module.
  78.  ****************************************************************************/
  79. /* create a new tooltipped area */
  80. #define TOOLTIP( text )                                                   
  81.     /* create an event box to catch some events */                        
  82.     item_event_box = gtk_event_box_new();                                 
  83.     /* add a tooltip on mouseover */                                      
  84.     gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,                      
  85.                           item_event_box, text, "" );                     
  86.     gtk_container_set_border_width( GTK_CONTAINER(item_event_box), 4 );
  87. /* draws a right aligned label in side of a widget */
  88. #define LABEL_AND_WIDGET( label_text, widget, tooltip )                   
  89.     gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );             
  90.     item_align = gtk_alignment_new( 1, .5, 0, 0 );                        
  91.     item_label = gtk_label_new( label_text );                             
  92.     gtk_container_add( GTK_CONTAINER(item_align), item_label );           
  93.     gtk_table_attach_defaults( GTK_TABLE(category_table), item_align,     
  94.                                0, 1, rows - 1, rows );                    
  95.     item_align = gtk_alignment_new( 0, .5, .5, 0 );                       
  96.     gtk_container_add( GTK_CONTAINER(item_align), widget );               
  97.     TOOLTIP(tooltip)                                                      
  98.     gtk_container_add( GTK_CONTAINER(item_event_box), item_align );       
  99.     gtk_table_attach_defaults( GTK_TABLE(category_table), item_event_box, 
  100.                                1, 2, rows - 1, rows );
  101. static void GtkCreateConfigDialog( char *psz_module_name,
  102.                                    intf_thread_t *p_intf )
  103. {
  104.     module_t *p_parser = NULL;
  105.     vlc_list_t *p_list;
  106.     module_config_t *p_item;
  107.     vlc_bool_t b_advanced = config_GetInt( p_intf, "advanced" );
  108.     int i_index;
  109.     guint rows = 0;
  110.     GHashTable *config_hash_table;
  111.     GtkWidget *item_event_box;
  112.     GtkWidget *config_dialog;
  113.     GtkWidget *config_dialog_vbox;
  114.     GtkWidget *config_notebook;
  115.     GtkWidget *category_table = NULL;
  116.     GtkWidget *category_label = NULL;
  117. #ifndef MODULE_NAME_IS_gnome
  118.     GtkWidget *dialog_action_area;
  119. #endif
  120.     GtkWidget *ok_button;
  121.     GtkWidget *apply_button;
  122.     GtkWidget *save_button;
  123.     GtkWidget *cancel_button;
  124.     GtkWidget *item_align;
  125.     GtkWidget *item_frame;
  126.     GtkWidget *item_hbox;
  127.     GtkWidget *item_label;
  128.     GtkWidget *item_vbox;
  129.     GtkWidget *item_combo;
  130.     GtkWidget *string_entry;
  131.     GtkWidget *integer_spinbutton;
  132.     GtkWidget *integer_slider;
  133.     GtkWidget *float_spinbutton;
  134.     GtkWidget *float_slider;
  135.     GtkObject *item_adj;
  136.     GtkWidget *bool_checkbutton;
  137.     GtkWidget *module_clist;
  138.     GtkWidget *module_config_button;
  139.     GtkWidget *module_select_button;
  140.     gint category_max_height;
  141.     /* Check if the dialog box is already opened because we don't want to
  142.      * duplicate identical dialog windows. */
  143.     config_dialog = (GtkWidget *)gtk_object_get_data(
  144.                     GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name );
  145.     if( config_dialog )
  146.     {
  147.         /* Yeah it was open */
  148.         gtk_widget_grab_focus( config_dialog );
  149.         return;
  150.     }
  151.     /* Look for the selected module */
  152.     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
  153.     for( i_index = 0; i_index < p_list->i_count; i_index++ )
  154.     {
  155.         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
  156.         if( psz_module_name
  157.              && !strcmp( psz_module_name, p_parser->psz_object_name ) )
  158.         {
  159.             break;
  160.         }
  161.     }
  162.     if( !p_parser || i_index == p_list->i_count )
  163.     {
  164.         vlc_list_release( p_list );
  165.         return;
  166.     }
  167.     /* We found it, now we can start building its configuration interface */
  168.     /* Create the configuration dialog box */
  169. #ifdef MODULE_NAME_IS_gnome
  170.     config_dialog = gnome_dialog_new( p_parser->psz_longname, NULL );
  171.     config_dialog_vbox = GNOME_DIALOG(config_dialog)->vbox;
  172. #else
  173.     config_dialog = gtk_dialog_new();
  174.     gtk_window_set_title( GTK_WINDOW(config_dialog),
  175.                           p_parser->psz_longname );
  176.     config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox;
  177. #endif
  178.     gtk_object_set_data( GTK_OBJECT(config_dialog), "p_intf", p_intf );
  179.     category_max_height = config_GetInt( p_intf, MODULE_STRING "-prefs-maxh" );
  180.     gtk_window_set_policy( GTK_WINDOW(config_dialog), TRUE, TRUE, FALSE );
  181.     gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 );
  182.     /* Create our config hash table and associate it with the dialog box */
  183.     config_hash_table = g_hash_table_new( NULL, NULL );
  184.     gtk_object_set_data( GTK_OBJECT(config_dialog),
  185.                          "config_hash_table", config_hash_table );
  186.     /* Create notebook */
  187.     config_notebook = gtk_notebook_new();
  188.     gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE );
  189.     gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook );
  190.     /* Enumerate config options and add corresponding config boxes */
  191.     p_item = p_parser->p_config;
  192.     if( p_item ) do
  193.     {
  194.         if( p_item->b_advanced && !b_advanced ) continue;
  195.         if( p_item->i_type == CONFIG_HINT_CATEGORY ||
  196.             p_item->i_type == CONFIG_HINT_END ||
  197.             !category_table )
  198.         {
  199.             /*
  200.              * Before we start building the interface for the new category, we
  201.              * must close/finish the previous one we were generating.
  202.              */
  203.             if( category_table )
  204.             {
  205.                 GtkWidget *_scrolled_window;
  206.                 GtkWidget *_viewport;
  207.                 GtkWidget *_vbox;
  208.                 GtkRequisition _requisition;
  209.                 /* create a vbox to deal with EXPAND/FILL issues in the
  210.                  * notebook page, and pack it with the previously generated
  211.                  * category_table */
  212.                 _vbox = gtk_vbox_new( FALSE, 0 );
  213.                 gtk_container_set_border_width( GTK_CONTAINER(_vbox), 4 );
  214.                 gtk_box_pack_start( GTK_BOX(_vbox), category_table,
  215.                                     FALSE, FALSE, 0 );
  216.                 /* create a new scrolled window that will contain all of the
  217.                  * above. */
  218.                 _scrolled_window = gtk_scrolled_window_new( NULL, NULL );
  219.                 gtk_scrolled_window_set_policy(
  220.                     GTK_SCROLLED_WINDOW(_scrolled_window), GTK_POLICY_NEVER,
  221.                     GTK_POLICY_AUTOMATIC );
  222.                 /* add scrolled window as a notebook page */
  223.                 gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook),
  224.                                           _scrolled_window, category_label );
  225.                 /* pack the vbox into the scrolled window */
  226.                 _viewport = gtk_viewport_new( NULL, NULL );
  227.                 gtk_viewport_set_shadow_type( GTK_VIEWPORT(_viewport),
  228.                                               GTK_SHADOW_NONE );
  229.                 gtk_container_add( GTK_CONTAINER(_viewport), _vbox );
  230.                 gtk_container_add( GTK_CONTAINER(_scrolled_window),
  231.                                    _viewport );
  232.                 /* set the size of the scrolled window to the size of the
  233.                  * child widget */
  234.                 gtk_widget_show_all( _vbox );
  235.                 gtk_widget_size_request( _vbox, &_requisition );
  236.                 if( _requisition.height > category_max_height )
  237.                     gtk_widget_set_usize( _scrolled_window, -1,
  238.                                           category_max_height );
  239.                 else
  240.                     gtk_widget_set_usize( _scrolled_window, -1,
  241.                                           _requisition.height );
  242.             }
  243.             /*
  244.              * Now we can start taking care of the new category
  245.              */
  246.             if( p_item->i_type != CONFIG_HINT_END )
  247.             {
  248.                 /* create a new table for right-left alignment of children */
  249.                 category_table = gtk_table_new( 0, 0, FALSE );
  250.                 gtk_table_set_col_spacings( GTK_TABLE(category_table), 4 );
  251.                 rows = 0;
  252.                 /* create a new category label */
  253.                 if( p_item->i_type == CONFIG_HINT_CATEGORY )
  254.                     category_label = gtk_label_new( p_item->psz_text );
  255.                 else
  256.                     category_label = gtk_label_new( p_parser->psz_longname );
  257.             }
  258.         }
  259.         switch( p_item->i_type )
  260.         {
  261.         case CONFIG_ITEM_MODULE:
  262.             item_frame = gtk_frame_new( p_item->psz_text );
  263.             gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );
  264.             gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame,
  265.                                        0, 2, rows - 1, rows );
  266.             item_vbox = gtk_vbox_new( FALSE, 4 );
  267.             gtk_container_add( GTK_CONTAINER(item_frame), item_vbox );
  268.             /* create a new clist widget */
  269.             {
  270.                 gchar * titles[] = { N_("Name"), N_("Description") };
  271.                 titles[0] = _(titles[0]);
  272.                 titles[1] = _(titles[1]);
  273.                 module_clist = gtk_clist_new_with_titles( 2, titles );
  274.             }
  275.             gtk_object_set_data( GTK_OBJECT(module_clist), "p_intf", p_intf );
  276.             gtk_clist_column_titles_passive( GTK_CLIST(module_clist) );
  277.             gtk_clist_set_selection_mode( GTK_CLIST(module_clist),
  278.                                           GTK_SELECTION_SINGLE);
  279.             gtk_container_add( GTK_CONTAINER(item_vbox), module_clist );
  280.             /* build a list of available modules */
  281.             {
  282.                 gchar * entry[2];
  283.                 for( i_index = 0; i_index < p_list->i_count; i_index++ )
  284.                 {
  285.                     p_parser = (module_t *)p_list->p_values[i_index].p_object ;
  286.                     if( !strcmp( p_parser->psz_capability,
  287.                                  p_item->psz_type ) )
  288.                     {
  289.                         entry[0] = p_parser->psz_object_name;
  290.                         entry[1] = p_parser->psz_longname;
  291.                         gtk_clist_append( GTK_CLIST(module_clist), entry );
  292.                     }
  293.                 }
  294.             }
  295.             gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
  296.                                               0, TRUE );
  297.             gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
  298.                                               1, TRUE );
  299.             /* connect signals to the modules list */
  300.             gtk_signal_connect( GTK_OBJECT(module_clist), "select_row",
  301.                                 GTK_SIGNAL_FUNC(GtkModuleHighlighted),
  302.                                 NULL );
  303.             /* hbox holding the "select" and "configure" buttons */
  304.             item_hbox = gtk_hbox_new( FALSE, 4 );
  305.             gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
  306.             /* add configure button */
  307.             module_config_button =
  308.                 gtk_button_new_with_label( _("Configure") );
  309.             gtk_widget_set_sensitive( module_config_button, FALSE );
  310.             gtk_container_add( GTK_CONTAINER(item_hbox),
  311.                                module_config_button );
  312.             gtk_object_set_data( GTK_OBJECT(module_config_button),
  313.                                  "p_intf", p_intf );
  314.             gtk_object_set_data( GTK_OBJECT(module_clist),
  315.                                  "config_button", module_config_button );
  316.             /* add select button */
  317.             module_select_button =
  318.                 gtk_button_new_with_label( _("Select") );
  319.             gtk_container_add( GTK_CONTAINER(item_hbox),
  320.                                module_select_button );
  321.             /* add a tooltip on mouseover */
  322.             gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
  323.                                   module_select_button,
  324.                                   p_item->psz_longtext, "" );
  325.             /* hbox holding the "selected" label and text input */
  326.             item_hbox = gtk_hbox_new( FALSE, 4 );
  327.             gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
  328.             /* add new label */
  329.             item_label = gtk_label_new( _("Selected:") );
  330.             gtk_container_add( GTK_CONTAINER(item_hbox), item_label );
  331.             /* add input box with default value */
  332.             string_entry = gtk_entry_new();
  333.             gtk_object_set_data( GTK_OBJECT(module_clist),
  334.                                  "module_entry", string_entry );
  335.             gtk_container_add( GTK_CONTAINER(item_hbox), string_entry );
  336.             vlc_mutex_lock( p_item->p_lock );
  337.             gtk_entry_set_text( GTK_ENTRY(string_entry),
  338.                                 p_item->psz_value ? p_item->psz_value : "" );
  339.             vlc_mutex_unlock( p_item->p_lock );
  340.             /* add a tooltip on mouseover */
  341.             gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
  342.                                   string_entry, p_item->psz_longtext, "" );
  343.             /* connect signals to the buttons */
  344.             gtk_signal_connect( GTK_OBJECT(module_config_button), "clicked",
  345.                                 GTK_SIGNAL_FUNC(GtkModuleConfigure),
  346.                                 (gpointer)module_clist );
  347.             gtk_signal_connect( GTK_OBJECT(module_select_button), "clicked",
  348.                                 GTK_SIGNAL_FUNC(GtkModuleSelected),
  349.                                 (gpointer)module_clist );
  350.             /* connect signal to track changes in the text box */
  351.             gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
  352.                                  p_item->psz_name );
  353.             gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
  354.                                 GTK_SIGNAL_FUNC(GtkStringChanged),
  355.                                 (gpointer)config_dialog );
  356.             break;
  357.         case CONFIG_ITEM_STRING:
  358.         case CONFIG_ITEM_FILE:
  359.         case CONFIG_ITEM_DIRECTORY:
  360.             if( !p_item->ppsz_list )
  361.             {
  362.                 /* add input box with default value */
  363.                 item_combo = string_entry = gtk_entry_new();
  364.             }
  365.             else
  366.             {
  367.                 /* add combo box with default value */
  368.                 GList *items = NULL;
  369.                 int i;
  370.                 for( i=0; p_item->ppsz_list[i]; i++ )
  371.                     items = g_list_append( items, p_item->ppsz_list[i] );
  372.                 item_combo = gtk_combo_new();
  373.                 string_entry = GTK_COMBO(item_combo)->entry;
  374.                 gtk_combo_set_popdown_strings( GTK_COMBO(item_combo),
  375.                                                items );
  376.             }
  377.             vlc_mutex_lock( p_item->p_lock );
  378.             gtk_entry_set_text( GTK_ENTRY(string_entry),
  379.                                 p_item->psz_value ? p_item->psz_value : "" );
  380.             vlc_mutex_unlock( p_item->p_lock );
  381.             /* connect signal to track changes in the text box */
  382.             gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
  383.                                  p_item->psz_name );
  384.             gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
  385.                                 GTK_SIGNAL_FUNC(GtkStringChanged),
  386.                                 (gpointer)config_dialog );
  387.             LABEL_AND_WIDGET( p_item->psz_text,
  388.                               item_combo, p_item->psz_longtext );
  389.             break;
  390.         case CONFIG_ITEM_INTEGER:
  391.             if (( p_item->i_max == 0) && ( p_item->i_min == 0))
  392.             {
  393.                 /* add input box with default value */
  394.                 item_adj = gtk_adjustment_new( p_item->i_value,
  395.                                                -1, 99999, 1, 10, 10 );
  396.                 integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj), 1, 0 );
  397.                 /* connect signal to track changes in the spinbutton value */
  398.                 gtk_object_set_data( GTK_OBJECT(integer_spinbutton),
  399.                                      "config_option", p_item->psz_name );
  400.                 gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed",
  401.                                     GTK_SIGNAL_FUNC(GtkIntChanged),
  402.                                     (gpointer)config_dialog );
  403.                 LABEL_AND_WIDGET( p_item->psz_text,
  404.                                   integer_spinbutton, p_item->psz_longtext );
  405.             }
  406.             else /* use i_min and i_max */
  407.             {
  408.                 item_adj = gtk_adjustment_new( p_item->i_value, p_item->i_min,
  409.                                                p_item->i_max, 1, 1, 0 );
  410.                 integer_slider = gtk_hscale_new( GTK_ADJUSTMENT(item_adj));
  411.                 gtk_scale_set_digits (GTK_SCALE(integer_slider), 0);
  412.                                                 
  413.                 /* connect signal to track changes in the spinbutton value */
  414.                 gtk_object_set_data( GTK_OBJECT(item_adj),
  415.                                      "config_option", p_item->psz_name );
  416.                 gtk_signal_connect( GTK_OBJECT(item_adj), "value-changed",
  417.                                     GTK_SIGNAL_FUNC(GtkIntRangedChanged),
  418.                                     (gpointer)config_dialog );
  419.                 LABEL_AND_WIDGET( p_item->psz_text,
  420.                                   integer_slider, p_item->psz_longtext );
  421.             }
  422.             break;
  423.         case CONFIG_ITEM_FLOAT:
  424.             if (( p_item->f_max == 0.0) && ( p_item->f_min == 0.0))
  425.             {
  426.                 /* add input box with default value */
  427.                 item_adj = gtk_adjustment_new( p_item->f_value,
  428.                                                0, 99999, 0.01, 10, 10 );
  429.                 float_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
  430.                                                         0.01, 2 );
  431.                 /* connect signal to track changes in the spinbutton value */
  432.                 gtk_object_set_data( GTK_OBJECT(float_spinbutton),
  433.                                      "config_option", p_item->psz_name );
  434.                 gtk_signal_connect( GTK_OBJECT(float_spinbutton), "changed",
  435.                                     GTK_SIGNAL_FUNC(GtkFloatChanged),
  436.                                     (gpointer)config_dialog );
  437.                 LABEL_AND_WIDGET( p_item->psz_text,
  438.                                   float_spinbutton, p_item->psz_longtext );
  439.             }
  440.             else /* use f_min and f_max */
  441.             {
  442.                 item_adj = gtk_adjustment_new( p_item->f_value, p_item->f_min,
  443.                                                p_item->f_max, 0.01, 0.01, 0 );
  444.                 float_slider = gtk_hscale_new( GTK_ADJUSTMENT(item_adj));
  445.                 gtk_scale_set_digits (GTK_SCALE(float_slider), 2);
  446.                                                 
  447.                 /* connect signal to track changes in the spinbutton value */
  448.                 gtk_object_set_data( GTK_OBJECT(item_adj),
  449.                                      "config_option", p_item->psz_name );
  450.                 gtk_signal_connect( GTK_OBJECT(item_adj), "value-changed",
  451.                                     GTK_SIGNAL_FUNC(GtkFloatRangedChanged),
  452.                                     (gpointer)config_dialog );
  453.                 LABEL_AND_WIDGET( p_item->psz_text,
  454.                                   float_slider, p_item->psz_longtext );
  455.             }
  456.             break;
  457.         case CONFIG_ITEM_BOOL:
  458.             /* add check button */
  459.             bool_checkbutton = gtk_check_button_new();
  460.             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton),
  461.                                           p_item->i_value );
  462.             /* connect signal to track changes in the button state */
  463.             gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option",
  464.                                  p_item->psz_name );
  465.             gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled",
  466.                                 GTK_SIGNAL_FUNC(GtkBoolChanged),
  467.                                 (gpointer)config_dialog );
  468.             LABEL_AND_WIDGET( p_item->psz_text,
  469.                               bool_checkbutton, p_item->psz_longtext );
  470.             break;
  471.         }
  472.     }
  473.     while( p_item->i_type != CONFIG_HINT_END && p_item++ );
  474.     vlc_list_release( p_list );
  475. #ifndef MODULE_NAME_IS_gnome
  476.     /* Now let's add the action buttons at the bottom of the page */
  477.     dialog_action_area = GTK_DIALOG(config_dialog)->action_area;
  478.     gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 );
  479.     /* add a new table for the config option */
  480.     item_hbox = gtk_hbox_new( FALSE, 0 );
  481.     gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
  482.                       TRUE, FALSE, 0 );
  483.     item_hbox = gtk_hbox_new( FALSE, 0 );
  484.     gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
  485.                       TRUE, FALSE, 0 );
  486. #endif
  487.     /* Create the OK button */
  488. #ifdef MODULE_NAME_IS_gnome
  489.     gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
  490.                                 GNOME_STOCK_BUTTON_OK );
  491.     ok_button =
  492.         GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
  493.     gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
  494.                                 GNOME_STOCK_BUTTON_APPLY );
  495.     apply_button =
  496.         GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
  497.     gnome_dialog_append_button_with_pixmap(
  498.         GNOME_DIALOG(config_dialog), _("Save"), GNOME_STOCK_PIXMAP_SAVE );
  499.     save_button =
  500.         GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
  501.     gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
  502.                                 GNOME_STOCK_BUTTON_CANCEL );
  503.     cancel_button =
  504.         GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
  505. #else
  506.     ok_button = gtk_button_new_with_label( _("OK") );
  507.     gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button,
  508.                         TRUE, TRUE, 0 );
  509.     apply_button = gtk_button_new_with_label( _("Apply") );
  510.     gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button,
  511.                         TRUE, TRUE, 0 );
  512.     save_button = gtk_button_new_with_label( _("Save") );
  513.     gtk_box_pack_start( GTK_BOX(dialog_action_area), save_button,
  514.                         TRUE, TRUE, 0 );
  515.     cancel_button = gtk_button_new_with_label( _("Cancel") );
  516.     gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button,
  517.                         TRUE, TRUE, 0 );
  518. #endif
  519.     gtk_signal_connect( GTK_OBJECT(ok_button), "clicked",
  520.                         GTK_SIGNAL_FUNC(GtkConfigOk),
  521.                         config_dialog );
  522.     gtk_widget_set_sensitive( apply_button, FALSE );
  523.     gtk_object_set_data( GTK_OBJECT(config_dialog), "apply_button",
  524.                          apply_button );
  525.     gtk_signal_connect( GTK_OBJECT(apply_button), "clicked",
  526.                         GTK_SIGNAL_FUNC(GtkConfigApply),
  527.                         config_dialog );
  528.     gtk_signal_connect( GTK_OBJECT(save_button), "clicked",
  529.                         GTK_SIGNAL_FUNC(GtkConfigSave),
  530.                         config_dialog );
  531.     gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked",
  532.                         GTK_SIGNAL_FUNC(GtkConfigCancel),
  533.                         config_dialog );
  534.     /* Ok, job done successfully. Let's keep a reference to the dialog box */
  535.     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
  536.                          psz_module_name, config_dialog );
  537.     gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name",
  538.                          psz_module_name );
  539.     /* we want this ref to be destroyed if the object is destroyed */
  540.     gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy",
  541.                        GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed),
  542.                        (gpointer)p_intf );
  543.     gtk_widget_show_all( config_dialog );
  544. }
  545. #undef LABEL_AND_WIDGET
  546. #undef TOOLTIP
  547. /****************************************************************************
  548.  * GtkConfigApply: store the changes to the config inside the modules
  549.  * configuration structure and clear the hash table.
  550.  ****************************************************************************/
  551. static void GtkConfigApply( GtkButton * button, gpointer user_data )
  552. {
  553.     intf_thread_t *p_intf;
  554.     GHashTable *hash_table;
  555.     GtkWidget *apply_button;
  556.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  557.                                                     "config_hash_table" );
  558.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
  559.                                                    "p_intf" );
  560.     g_hash_table_foreach_remove( hash_table, GtkSaveHashValue, (void*)p_intf );
  561.     /* change the highlight status of the Apply button */
  562.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  563.                                                     "apply_button" );
  564.     gtk_widget_set_sensitive( apply_button, FALSE );
  565. }
  566. static void GtkConfigOk( GtkButton * button, gpointer user_data )
  567. {
  568.     GtkConfigApply( button, user_data );
  569.     gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
  570. }
  571. static void GtkConfigCancel( GtkButton * button, gpointer user_data )
  572. {
  573.     gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
  574. }
  575. static void GtkConfigSave( GtkButton * button, gpointer user_data )
  576. {
  577.     intf_thread_t *p_intf;
  578.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
  579.                                                    "p_intf" );
  580.     GtkConfigApply( button, user_data );
  581.     config_SaveConfigFile( p_intf, NULL );
  582. }
  583. /****************************************************************************
  584.  * GtkModuleHighlighted: display module description when an entry is selected
  585.  *   in the clist, and activate the configure button if necessary.
  586.  ****************************************************************************/
  587. static void GtkModuleHighlighted( GtkCList *module_clist, int row, int column,
  588.                                   GdkEventButton *event, gpointer user_data )
  589. {
  590.     intf_thread_t *p_intf;
  591.     GtkWidget *config_button;
  592.     module_t *p_parser;
  593.     vlc_list_t *p_list;
  594.     char *psz_name;
  595.     int i_index;
  596.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(module_clist),
  597.                                                    "p_intf" );
  598.     if( !gtk_clist_get_text( GTK_CLIST(module_clist), row, 0, &psz_name ) )
  599.     {
  600.         return;
  601.     }
  602.     /* look for module 'psz_name' */
  603.     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
  604.     for( i_index = 0; i_index < p_list->i_count; i_index++ )
  605.     {
  606.         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
  607.         if( !strcmp( p_parser->psz_object_name, psz_name ) )
  608.         {
  609.             gtk_object_set_data( GTK_OBJECT(module_clist),
  610.                                  "module_highlighted", p_parser );
  611.             config_button = gtk_object_get_data( GTK_OBJECT(module_clist),
  612.                                                  "config_button" );
  613.             if( p_parser->i_config_items )
  614.                 gtk_widget_set_sensitive( config_button, TRUE );
  615.             else
  616.                 gtk_widget_set_sensitive( config_button, FALSE );
  617.             break;
  618.         }
  619.     }
  620.     vlc_list_release( p_list );
  621. }
  622. /****************************************************************************
  623.  * GtkModuleConfigure: display module configuration dialog box.
  624.  ****************************************************************************/
  625. static void GtkModuleConfigure( GtkButton *button, gpointer user_data )
  626. {
  627.     module_t *p_module;
  628.     intf_thread_t *p_intf;
  629.     p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
  630.                                                 "module_highlighted" );
  631.     if( !p_module ) return;
  632.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
  633.                                                    "p_intf" );
  634.     GtkCreateConfigDialog( p_module->psz_object_name, (gpointer)p_intf );
  635. }
  636. /****************************************************************************
  637.  * GtkModuleSelected: select module.
  638.  ****************************************************************************/
  639. static void GtkModuleSelected( GtkButton *button, gpointer user_data )
  640. {
  641.     module_t *p_module;
  642.     GtkWidget *widget;
  643.     p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
  644.                                                 "module_highlighted" );
  645.     widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  646.                                                "module_entry" );
  647.     if( !p_module ) return;
  648.     gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_object_name );
  649. }
  650. /****************************************************************************
  651.  * GtkStringChanged: signal called when the user changes a string value.
  652.  ****************************************************************************/
  653. static void GtkStringChanged( GtkEditable *editable, gpointer user_data )
  654. {
  655.     intf_thread_t *p_intf;
  656.     module_config_t *p_config;
  657.     GHashTable *hash_table;
  658.     GtkWidget *apply_button;
  659.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
  660.                                                    "p_intf" );
  661.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  662.                                                     "config_hash_table" );
  663.     /* free old p_config */
  664.     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
  665.                                                        (gpointer)editable );
  666.     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
  667.     p_config = malloc( sizeof(module_config_t) );
  668.     p_config->i_type = CONFIG_ITEM_STRING;
  669.     p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 );
  670.     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
  671.                                                       "config_option" );
  672.     g_hash_table_insert( hash_table, (gpointer)editable,
  673.                          (gpointer)p_config );
  674.     /* change the highlight status of the Apply button */
  675.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  676.                                                     "apply_button" );
  677.     gtk_widget_set_sensitive( apply_button, TRUE );
  678. }
  679. /****************************************************************************
  680.  * GtkIntChanged: signal called when the user changes an integer value.
  681.  ****************************************************************************/
  682. static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
  683. {
  684.     intf_thread_t *p_intf;
  685.     module_config_t *p_config;
  686.     GHashTable *hash_table;
  687.     GtkWidget *apply_button;
  688.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
  689.                                                    "p_intf" );
  690.     gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
  691.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  692.                                                     "config_hash_table" );
  693.     /* free old p_config */
  694.     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
  695.                                                        (gpointer)editable );
  696.     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
  697.     p_config = malloc( sizeof(module_config_t) );
  698.     p_config->i_type = CONFIG_ITEM_INTEGER;
  699.     p_config->i_value = gtk_spin_button_get_value_as_int(
  700.                             GTK_SPIN_BUTTON(editable) );
  701.     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
  702.                                                       "config_option" );
  703.     g_hash_table_insert( hash_table, (gpointer)editable,
  704.                          (gpointer)p_config );
  705.     /* change the highlight status of the Apply button */
  706.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  707.                                                     "apply_button" );
  708.     gtk_widget_set_sensitive( apply_button, TRUE );
  709. }
  710. /***************************************************************************************
  711.  * GtkIntRangedChanged: signal called when the user changes an integer with range value.
  712.  **************************************************************************************/
  713. static void GtkIntRangedChanged( GtkEditable *editable, gpointer user_data )
  714. {
  715.     intf_thread_t *p_intf;
  716.     module_config_t *p_config;
  717.     GHashTable *hash_table;
  718.     GtkWidget *apply_button;
  719.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
  720.                                                    "p_intf" );
  721.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  722.                                                     "config_hash_table" );
  723.     /* free old p_config */
  724.     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
  725.                                                        (gpointer)editable );
  726.     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
  727.     p_config = malloc( sizeof(module_config_t) );
  728.     p_config->i_type = CONFIG_ITEM_INTEGER;
  729.     p_config->i_value = ((GTK_ADJUSTMENT(editable))->value);
  730.     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
  731.                                                       "config_option" );
  732.     g_hash_table_insert( hash_table, (gpointer)editable,
  733.                          (gpointer)p_config );
  734.     /* change the highlight status of the Apply button */
  735.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  736.                                                     "apply_button" );
  737.     gtk_widget_set_sensitive( apply_button, TRUE );
  738. }
  739. /****************************************************************************
  740.  * GtkFloatChanged: signal called when the user changes a float value.
  741.  ****************************************************************************/
  742. static void GtkFloatChanged( GtkEditable *editable, gpointer user_data )
  743. {
  744.     intf_thread_t *p_intf;
  745.     module_config_t *p_config;
  746.     GHashTable *hash_table;
  747.     GtkWidget *apply_button;
  748.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
  749.                                                    "p_intf" );
  750.     gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
  751.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  752.                                                     "config_hash_table" );
  753.     /* free old p_config */
  754.     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
  755.                                                        (gpointer)editable );
  756.     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
  757.     p_config = malloc( sizeof(module_config_t) );
  758.     p_config->i_type = CONFIG_ITEM_FLOAT;
  759.     p_config->f_value = gtk_spin_button_get_value_as_float(
  760.                            GTK_SPIN_BUTTON(editable) );
  761.     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
  762.                                                       "config_option" );
  763.     g_hash_table_insert( hash_table, (gpointer)editable,
  764.                          (gpointer)p_config );
  765.     /* change the highlight status of the Apply button */
  766.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  767.                                                     "apply_button" );
  768.     gtk_widget_set_sensitive( apply_button, TRUE );
  769. }
  770. /***************************************************************************************
  771.  * GtkIntRangedChanged: signal called when the user changes an integer with range value.
  772.  **************************************************************************************/
  773. static void GtkFloatRangedChanged( GtkEditable *editable, gpointer user_data )
  774. {
  775.     intf_thread_t *p_intf;
  776.     module_config_t *p_config;
  777.     GHashTable *hash_table;
  778.     GtkWidget *apply_button;
  779.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
  780.                                                    "p_intf" );
  781.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  782.                                                     "config_hash_table" );
  783.     /* free old p_config */
  784.     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
  785.                                                        (gpointer)editable );
  786.     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
  787.     p_config = malloc( sizeof(module_config_t) );
  788.     p_config->i_type = CONFIG_ITEM_FLOAT;
  789.     p_config->f_value = ((GTK_ADJUSTMENT(editable))->value);
  790.     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
  791.                                                       "config_option" );
  792.     g_hash_table_insert( hash_table, (gpointer)editable,
  793.                          (gpointer)p_config );
  794.     /* change the highlight status of the Apply button */
  795.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  796.                                                     "apply_button" );
  797.     gtk_widget_set_sensitive( apply_button, TRUE );
  798. }
  799. /****************************************************************************
  800.  * GtkBoolChanged: signal called when the user changes a bool value.
  801.  ****************************************************************************/
  802. static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data )
  803. {
  804.     intf_thread_t *p_intf;
  805.     module_config_t *p_config;
  806.     GHashTable *hash_table;
  807.     GtkWidget *apply_button;
  808.     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
  809.                                                    "p_intf" );
  810.     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
  811.                                                     "config_hash_table" );
  812.     /* free old p_config */
  813.     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
  814.                                                        (gpointer)button );
  815.     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
  816.     p_config = malloc( sizeof(module_config_t) );
  817.     p_config->i_type = CONFIG_ITEM_BOOL;
  818.     p_config->i_value = gtk_toggle_button_get_active( button );
  819.     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button),
  820.                                                       "config_option" );
  821.     g_hash_table_insert( hash_table, (gpointer)button,
  822.                          (gpointer)p_config );
  823.     /* change the highlight status of the Apply button */
  824.     apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
  825.                                                      "apply_button" );
  826.     gtk_widget_set_sensitive( apply_button, TRUE );
  827. }
  828. /****************************************************************************
  829.  * GtkFreeHashTable: signal called when the config hash table is destroyed.
  830.  ****************************************************************************/
  831. static void GtkFreeHashTable( GtkObject *object )
  832. {
  833.     GHashTable *hash_table = (GHashTable *)gtk_object_get_data( object,
  834.                                                          "config_hash_table" );
  835.     intf_thread_t *p_intf = (intf_thread_t *)gtk_object_get_data( object,
  836.                                                                   "p_intf" );
  837.     g_hash_table_foreach( hash_table, GtkFreeHashValue, (void *)p_intf );
  838.     g_hash_table_destroy( hash_table );
  839. }
  840. /****************************************************************************
  841.  * GtkFreeHashValue: signal called when an element of the config hash table
  842.  * is destroyed.
  843.  ****************************************************************************/
  844. static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data)
  845. {
  846.     module_config_t * p_config = (module_config_t *)value;
  847.     if( p_config->i_type == CONFIG_ITEM_STRING )
  848.         if( p_config->psz_value ) g_free( p_config->psz_value );
  849.     free( p_config );
  850. }
  851. /****************************************************************************
  852.  * GtkSaveHashValue: callback used when enumerating the hash table in
  853.  * GtkConfigApply().
  854.  ****************************************************************************/
  855. static gboolean GtkSaveHashValue( gpointer key, gpointer value,
  856.                                   gpointer user_data )
  857. {
  858.     intf_thread_t *   p_intf   = (intf_thread_t *)user_data;
  859.     module_config_t * p_config = (module_config_t *)value;
  860.     switch( p_config->i_type )
  861.     {
  862.     case CONFIG_ITEM_STRING:
  863.     case CONFIG_ITEM_FILE:
  864.     case CONFIG_ITEM_DIRECTORY:
  865.     case CONFIG_ITEM_MODULE:
  866.         config_PutPsz( p_intf, p_config->psz_name,
  867.                        *p_config->psz_value ? p_config->psz_value : NULL );
  868.         break;
  869.     case CONFIG_ITEM_INTEGER:
  870.     case CONFIG_ITEM_BOOL:
  871.         config_PutInt( p_intf, p_config->psz_name, p_config->i_value );
  872.         break;
  873.     case CONFIG_ITEM_FLOAT:
  874.         config_PutFloat( p_intf, p_config->psz_name, p_config->f_value );
  875.         break;
  876.     }
  877.     /* free the hash value we allocated */
  878.     if( p_config->i_type == CONFIG_ITEM_STRING )
  879.         g_free( p_config->psz_value );
  880.     free( p_config );
  881.     /* return TRUE so glib will free the hash entry */
  882.     return TRUE;
  883. }
  884. /****************************************************************************
  885.  * GtkConfigDialogDestroyed: callback triggered when the config dialog box is
  886.  * destroyed.
  887.  ****************************************************************************/
  888. static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data )
  889. {
  890.     intf_thread_t *p_intf = (intf_thread_t *)user_data;
  891.     char *psz_module_name;
  892.     psz_module_name = gtk_object_get_data( object, "psz_module_name" );
  893.     /* remove the ref to the dialog box */
  894.     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
  895.                          psz_module_name, NULL );
  896.     GtkFreeHashTable( object );
  897. }