]> git.sesse.net Git - vlc/blob - plugins/gtk/gtk_preferences.c
2f74523ba7ce43b4f981362abca4c89cb05661e0
[vlc] / plugins / gtk / gtk_preferences.c
1 /*****************************************************************************
2  * gtk_preferences.c: functions to handle the preferences dialog box.
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: gtk_preferences.c,v 1.15 2002/03/25 20:37:00 lool Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
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
36 #include <videolan/vlc.h>
37
38 #ifdef MODULE_NAME_IS_gnome
39 #   include <gnome.h>
40 #else
41 #   include <gtk/gtk.h>
42 #endif
43
44 #include <string.h>
45
46 #include "interface.h"
47
48 #include "gtk_support.h"
49 #include "gtk_common.h"
50 #include "gtk_preferences.h"
51
52 /* local functions */
53 static void GtkCreateConfigDialog( char *, intf_thread_t * );
54
55 static void GtkConfigOk          ( GtkButton *, gpointer );
56 static void GtkConfigApply       ( GtkButton *, gpointer );
57 static void GtkConfigCancel      ( GtkButton *, gpointer );
58
59 static void GtkConfigDialogDestroyed ( GtkObject *, gpointer );
60
61 static void GtkStringChanged     ( GtkEditable *, gpointer );
62 static void GtkIntChanged        ( GtkEditable *, gpointer );
63 static void GtkBoolChanged       ( GtkToggleButton *, gpointer );
64
65 static void GtkFreeHashTable     ( gpointer );
66 static void GtkFreeHashValue     ( gpointer, gpointer, gpointer );
67 static void GtkSaveHashValue     ( gpointer, gpointer, gpointer );
68
69 static void GtkPluginConfigure   ( GtkButton *, gpointer );
70 static void GtkPluginSelected    ( GtkButton *, gpointer );
71 static void GtkPluginHighlighted ( GtkCList *, int, int, GdkEventButton *,
72                                    gpointer );
73
74 /****************************************************************************
75  * Callback for menuitems: display configuration interface window
76  ****************************************************************************/
77 void GtkPreferencesActivate( GtkMenuItem * menuitem, gpointer user_data )
78 {
79     intf_thread_t * p_intf;
80
81     p_intf = GetIntf( GTK_WIDGET(menuitem), (char*)user_data );
82
83     GtkCreateConfigDialog( "main", p_intf );
84 }
85
86 /****************************************************************************
87  * GtkCreateConfigDialog: dynamically creates the configuration dialog
88  * box from all the configuration data provided by the selected module.
89  ****************************************************************************/
90
91 /* create a new tooltipped area */
92 #define TOOLTIP( container, text, ev_box )                                \
93     /* create an event box to catch some events */                        \
94     ev_box = gtk_event_box_new();                                         \
95     gtk_container_add( GTK_CONTAINER(container), ev_box );                \
96     /* add a tooltip on mouseover */                                      \
97     /* FIXME: have a different text for the private text */               \
98     gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,                      \
99                           ev_box, text, text );                           \
100     gtk_container_set_border_width( GTK_CONTAINER(ev_box), 2 );
101
102 /* draws a right aligned label in side of a widget */
103 #define LABEL_AND_WIDGET( text, widget, hbox, label, align )              \
104     gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );             \
105     align = gtk_alignment_new( 1, .5, 0, 0 );                             \
106     label = gtk_label_new( text );                                        \
107     gtk_container_add( GTK_CONTAINER(align), label );                     \
108     gtk_table_attach_defaults( GTK_TABLE(category_table), align,          \
109                                0, 1, rows - 1, rows );                    \
110     align = gtk_alignment_new( 0, .5, 0, 0 );                             \
111     gtk_container_add( GTK_CONTAINER(align), widget );                    \
112     gtk_table_attach_defaults( GTK_TABLE(category_table), align,          \
113                                1, 2, rows - 1, rows );
114
115 static void GtkCreateConfigDialog( char *psz_module_name,
116                                    intf_thread_t *p_intf )
117 {
118     module_t *p_module, *p_module_bis;
119     int i;
120
121     guint rows = 0;
122
123     GHashTable *config_hash_table;
124
125     GtkWidget *item_event_box;
126
127     GtkWidget *config_dialog;
128     GtkWidget *config_dialog_vbox;
129     GtkWidget *config_notebook;
130     GtkWidget *category_table = NULL;
131     GtkWidget *category_vbox = NULL;
132
133     GtkWidget *dialog_action_area;
134     GtkWidget *ok_button;
135     GtkWidget *apply_button;
136     GtkWidget *cancel_button;
137
138     GtkWidget *item_align;
139     GtkWidget *item_frame;
140     GtkWidget *item_hbox;
141     GtkWidget *item_label;
142     GtkWidget *item_vbox;
143     GtkWidget *string_entry;
144     GtkWidget *integer_spinbutton;
145     GtkObject *item_adj;
146     GtkWidget *bool_checkbutton;
147     GtkWidget *plugin_clist;
148     GtkWidget *plugin_config_button;
149     GtkWidget *plugin_select_button;
150
151
152     /* Check if the dialog box is already opened, if so this will save us
153      * quite a bit of work. (the interface will be destroyed when you actually
154      * close the dialog window, but remember that it is only hidden if you
155      * clicked on the action buttons). This trick also allows us not to
156      * duplicate identical dialog windows. */
157
158     config_dialog = (GtkWidget *)gtk_object_get_data(
159                     GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name );
160     if( config_dialog )
161     {
162         /* Yeah it was open */
163         gtk_widget_show( config_dialog );
164         gtk_widget_grab_focus( config_dialog );
165         return;
166     }
167
168
169     /* Look for the selected module */
170     for( p_module = p_module_bank->first ; p_module != NULL ;
171          p_module = p_module->next )
172     {
173
174         if( psz_module_name && !strcmp( psz_module_name, p_module->psz_name ) )
175             break;
176     }
177     if( !p_module ) return;
178
179     /* We found it, now we can start building its configuration interface */
180     /* Create the configuration dialog box */
181     config_dialog = gtk_dialog_new();
182     gtk_window_set_title( GTK_WINDOW(config_dialog), p_module->psz_longname );
183
184     config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox;
185     gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 );
186
187     /* Create our config hash table and associate it with the dialog box */
188     config_hash_table = g_hash_table_new( NULL, NULL );
189     gtk_object_set_data_full( GTK_OBJECT(config_dialog),
190                               "config_hash_table", config_hash_table,
191                               (GtkDestroyNotify)GtkFreeHashTable );
192
193     /* Create notebook */
194     config_notebook = gtk_notebook_new();
195     gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE );
196     gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook );
197
198     /* Enumerate config options and add corresponding config boxes */
199     for( i = 0; i < p_module->i_config_lines; i++ )
200     {
201
202         switch( p_module->p_config[i].i_type )
203         {
204         case MODULE_CONFIG_HINT_CATEGORY:
205
206             /* pack a new vbox in the notebook */
207             category_vbox = gtk_vbox_new( FALSE, 2 );
208             gtk_container_set_border_width( GTK_CONTAINER(category_vbox), 2 );
209
210             /* add category vbox as a notebook page */
211             item_label = gtk_label_new( p_module->p_config[i].psz_text );
212             gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook),
213                                       category_vbox, item_label );
214
215             /* add a new table for right-left alignment */
216             category_table = gtk_table_new( 0, 0, FALSE );
217             gtk_table_set_col_spacings( GTK_TABLE(category_table), 2 );
218             rows = 0;
219             gtk_container_add( GTK_CONTAINER(category_vbox), category_table );
220
221             break;
222
223         case MODULE_CONFIG_ITEM_PLUGIN:
224
225             item_frame = gtk_frame_new( p_module->p_config[i].psz_text );
226
227             gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );
228             gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame,
229                                        0, 2, rows - 1, rows );
230
231             TOOLTIP( item_frame, p_module->p_config[i].psz_longtext,
232                      item_event_box )
233
234             item_vbox = gtk_vbox_new( FALSE, 2 );
235             gtk_container_add( GTK_CONTAINER(item_event_box), item_vbox );
236
237             /* create a new clist widget */
238             {
239                 gchar * titles[] = { "Name", "Description" };
240
241                 plugin_clist =
242                     gtk_clist_new_with_titles( 2, titles );
243             }
244             gtk_clist_column_titles_passive( GTK_CLIST(plugin_clist) );
245             gtk_clist_set_selection_mode( GTK_CLIST(plugin_clist),
246                                           GTK_SELECTION_SINGLE);
247             gtk_container_add( GTK_CONTAINER(item_vbox), plugin_clist );
248
249             /* build a list of available plugins */
250             {
251                 gchar * entry[2];
252
253                 for( p_module_bis = p_module_bank->first ;
254                      p_module_bis != NULL ;
255                      p_module_bis = p_module_bis->next )
256                 {
257                     if( p_module_bis->i_capabilities &
258                         (1 << p_module->p_config[i].i_value) )
259                     {
260                         entry[0] = p_module_bis->psz_name;
261                         entry[1] = p_module_bis->psz_longname;
262                         gtk_clist_append( GTK_CLIST(plugin_clist), entry );
263                     }
264                 }
265             }
266
267             gtk_clist_set_column_auto_resize( GTK_CLIST(plugin_clist),
268                                               0, TRUE );
269             gtk_clist_set_column_auto_resize( GTK_CLIST(plugin_clist),
270                                               1, TRUE );
271
272             /* connect signals to the plugins list */
273             gtk_signal_connect( GTK_OBJECT(plugin_clist), "select_row",
274                                 GTK_SIGNAL_FUNC(GtkPluginHighlighted),
275                                 NULL );
276
277             /* hbox holding the "select" and "configure" buttons */
278             item_hbox = gtk_hbox_new( FALSE, 2 );
279             gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
280
281             /* add configure button */
282             plugin_config_button =
283                 gtk_button_new_with_label( _("Configure") );
284             gtk_widget_set_sensitive( plugin_config_button, FALSE );
285             gtk_container_add( GTK_CONTAINER(item_hbox),
286                                plugin_config_button );
287             gtk_object_set_data( GTK_OBJECT(plugin_config_button),
288                                  "p_intf", p_intf );
289             gtk_object_set_data( GTK_OBJECT(plugin_clist),
290                                  "config_button", plugin_config_button );
291
292             /* add select button */
293             plugin_select_button =
294                 gtk_button_new_with_label( _("Select") );
295             gtk_container_add( GTK_CONTAINER(item_hbox),
296                                plugin_select_button );
297
298             /* hbox holding the "selected" label and text input */
299             item_hbox = gtk_hbox_new( FALSE, 2 );
300             gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
301             /* add new label */
302             item_label = gtk_label_new( _("Selected:") );
303             gtk_container_add( GTK_CONTAINER(item_hbox), item_label );
304
305             /* add input box with default value */
306             string_entry = gtk_entry_new();
307             gtk_object_set_data( GTK_OBJECT(plugin_clist),
308                                  "plugin_entry", string_entry );
309             gtk_container_add( GTK_CONTAINER(item_hbox), string_entry );
310             vlc_mutex_lock( p_module->p_config[i].p_lock );
311             gtk_entry_set_text( GTK_ENTRY(string_entry),
312                                 p_module->p_config[i].psz_value ?
313                                 p_module->p_config[i].psz_value : "" );
314             vlc_mutex_unlock( p_module->p_config[i].p_lock );
315
316             /* connect signals to the buttons */
317             gtk_signal_connect( GTK_OBJECT(plugin_config_button), "clicked",
318                                 GTK_SIGNAL_FUNC(GtkPluginConfigure),
319                                 (gpointer)plugin_clist );
320             gtk_signal_connect( GTK_OBJECT(plugin_select_button), "clicked",
321                                 GTK_SIGNAL_FUNC(GtkPluginSelected),
322                                 (gpointer)plugin_clist );
323
324             /* connect signal to track changes in the text box */
325             gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
326                                  p_module->p_config[i].psz_name );
327             gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
328                                 GTK_SIGNAL_FUNC(GtkStringChanged),
329                                 (gpointer)config_dialog );
330             break;
331
332         case MODULE_CONFIG_ITEM_STRING:
333         case MODULE_CONFIG_ITEM_FILE:
334
335             /* add input box with default value */
336             string_entry = gtk_entry_new();
337             vlc_mutex_lock( p_module->p_config[i].p_lock );
338             gtk_entry_set_text( GTK_ENTRY(string_entry),
339                                 p_module->p_config[i].psz_value ?
340                                 p_module->p_config[i].psz_value : "" );
341             vlc_mutex_unlock( p_module->p_config[i].p_lock );
342
343             /* connect signal to track changes in the text box */
344             gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
345                                  p_module->p_config[i].psz_name );
346             gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
347                                 GTK_SIGNAL_FUNC(GtkStringChanged),
348                                 (gpointer)config_dialog );
349
350             TOOLTIP( category_vbox, p_module->p_config[i].psz_longtext,
351                      item_event_box )
352
353             LABEL_AND_WIDGET( p_module->p_config[i].psz_text, string_entry,
354                               item_hbox, item_label, item_align );
355             break;
356
357         case MODULE_CONFIG_ITEM_INTEGER:
358
359             /* add input box with default value */
360             item_adj = gtk_adjustment_new( p_module->p_config[i].i_value,
361                                            -1, 1000, 1, 10, 10 );
362             integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
363                                                       1, 0 );
364
365             /* connect signal to track changes in the spinbutton value */
366             gtk_object_set_data( GTK_OBJECT(integer_spinbutton),
367                                  "config_option",
368                                  p_module->p_config[i].psz_name );
369             gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed",
370                                 GTK_SIGNAL_FUNC(GtkIntChanged),
371                                 (gpointer)config_dialog );
372
373             TOOLTIP( category_vbox, p_module->p_config[i].psz_longtext,
374                      item_event_box )
375
376             LABEL_AND_WIDGET( p_module->p_config[i].psz_text,
377                               integer_spinbutton, item_hbox, item_label,
378                               item_align );
379             break;
380
381         case MODULE_CONFIG_ITEM_BOOL:
382
383             /* add check button */
384             bool_checkbutton = gtk_check_button_new();
385             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton),
386                                           p_module->p_config[i].i_value );
387
388             /* connect signal to track changes in the button state */
389             gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option",
390                                  p_module->p_config[i].psz_name );
391             gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled",
392                                 GTK_SIGNAL_FUNC(GtkBoolChanged),
393                                 (gpointer)config_dialog );
394
395             TOOLTIP( category_vbox, p_module->p_config[i].psz_longtext,
396                      item_event_box )
397
398             LABEL_AND_WIDGET( p_module->p_config[i].psz_text, bool_checkbutton,
399                               item_hbox, item_label, item_align );
400             break;
401         }
402     }
403
404     /* Now let's add the action buttons at the bottom of the page */
405
406     dialog_action_area = GTK_DIALOG(config_dialog)->action_area;
407     gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 );
408
409     /* add a new table for the config option */
410     item_hbox = gtk_hbox_new( FALSE, 0 );
411     gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
412                       TRUE, FALSE, 0 );
413     item_hbox = gtk_hbox_new( FALSE, 0 );
414     gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
415                       TRUE, FALSE, 0 );
416
417     /* Create the OK button */
418     ok_button = gtk_button_new_with_label( _("Ok") );
419     gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button,
420                         TRUE, TRUE, 0 );
421
422     apply_button = gtk_button_new_with_label( _("Apply") );
423     gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button,
424                         TRUE, TRUE, 0 );
425
426     cancel_button = gtk_button_new_with_label( _("Cancel") );
427     gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button,
428                         TRUE, TRUE, 0 );
429
430     gtk_signal_connect( GTK_OBJECT(ok_button), "clicked",
431                         GTK_SIGNAL_FUNC(GtkConfigOk),
432                         config_dialog );
433     gtk_signal_connect( GTK_OBJECT(apply_button), "clicked",
434                         GTK_SIGNAL_FUNC(GtkConfigApply),
435                         config_dialog );
436     gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked",
437                         GTK_SIGNAL_FUNC(GtkConfigCancel),
438                         config_dialog );
439
440     /* Ok, job done successfully. Let's keep a reference to the dialog box */
441     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
442                          psz_module_name, config_dialog );
443     gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name",
444                          psz_module_name );
445
446     /* we want this ref to be destroyed if the object is destroyed */
447     gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy",
448                        GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed),
449                        (gpointer)p_intf );
450
451     gtk_widget_show_all( config_dialog );
452 }
453
454 #undef FRAME
455 #undef SCROLLED_WINDOW
456 #undef LABEL
457 #undef TOOLTIP
458
459 /****************************************************************************
460  * GtkConfigApply: store the changes to the config inside the modules
461  * configuration structure
462  ****************************************************************************/
463 void GtkConfigApply( GtkButton * button, gpointer user_data )
464 {
465     GHashTable *hash_table;
466     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
467                                                     "config_hash_table" );
468     g_hash_table_foreach( hash_table, GtkSaveHashValue, NULL );
469
470 }
471
472 void GtkConfigOk( GtkButton * button, gpointer user_data )
473 {
474     GtkConfigApply( button, user_data );
475     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
476 }
477
478
479 void GtkConfigCancel( GtkButton * button, gpointer user_data )
480 {
481     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
482 }
483
484 /****************************************************************************
485  * GtkPluginHighlighted: display plugin description when an entry is selected
486  *   in the clist, and activate the configure button if necessary.
487  ****************************************************************************/
488 void GtkPluginHighlighted( GtkCList *plugin_clist, int row, int column,
489                            GdkEventButton *event, gpointer user_data )
490 {
491     GtkWidget *config_button;
492     module_t *p_module;
493     char *psz_name;
494
495     if( gtk_clist_get_text( GTK_CLIST(plugin_clist), row, 0, &psz_name ) )
496     {
497         /* look for plugin 'psz_name' */
498         for( p_module = p_module_bank->first ;
499              p_module != NULL ;
500              p_module = p_module->next )
501         {
502           if( !strcmp( p_module->psz_name, psz_name ) )
503           {
504               gtk_object_set_data( GTK_OBJECT(plugin_clist),
505                                    "plugin_highlighted", p_module );
506               config_button = gtk_object_get_data( GTK_OBJECT(plugin_clist),
507                                                    "config_button" );
508               if( p_module->i_config_items )
509                   gtk_widget_set_sensitive( config_button, TRUE );
510               else
511                   gtk_widget_set_sensitive( config_button, FALSE );
512
513               break;
514           }
515         }
516
517     }
518 }
519
520 /****************************************************************************
521  * GtkPluginConfigure: display plugin configuration dialog box.
522  ****************************************************************************/
523 void GtkPluginConfigure( GtkButton *button, gpointer user_data )
524 {
525     module_t *p_module;
526     intf_thread_t *p_intf;
527
528     p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
529                                                 "plugin_highlighted" );
530
531     if( !p_module ) return;
532     p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
533                                                    "p_intf" );
534     GtkCreateConfigDialog( p_module->psz_name, (gpointer)p_intf );
535
536 }
537
538 /****************************************************************************
539  * GtkPluginSelected: select plugin.
540  ****************************************************************************/
541 void GtkPluginSelected( GtkButton *button, gpointer user_data )
542 {
543     module_t *p_module;
544     GtkWidget *widget;
545
546     p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
547                                                 "plugin_highlighted" );
548     widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
549                                                "plugin_entry" );
550     if( !p_module ) return;
551
552     gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_name );
553
554 }
555
556 /****************************************************************************
557  * GtkStringChanged: signal called when the user changes a string value.
558  ****************************************************************************/
559 static void GtkStringChanged( GtkEditable *editable, gpointer user_data )
560 {
561     module_config_t *p_config;
562
563     GHashTable *hash_table;
564
565     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
566                                                     "config_hash_table" );
567     /* free old p_config */
568     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
569                                                        (gpointer)editable );
570     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
571
572     p_config = malloc( sizeof(module_config_t) );
573     p_config->i_type = MODULE_CONFIG_ITEM_STRING;
574     p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 );
575     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
576                                                       "config_option" );
577
578     g_hash_table_insert( hash_table, (gpointer)editable,
579                          (gpointer)p_config );
580 }
581
582 /****************************************************************************
583  * GtkIntChanged: signal called when the user changes a an integer value.
584  ****************************************************************************/
585 static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
586 {
587     module_config_t *p_config;
588
589     GHashTable *hash_table;
590
591     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
592                                                     "config_hash_table" );
593
594     /* free old p_config */
595     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
596                                                        (gpointer)editable );
597     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
598
599     p_config = malloc( sizeof(module_config_t) );
600     p_config->i_type = MODULE_CONFIG_ITEM_INTEGER;
601     p_config->i_value =  gtk_spin_button_get_value_as_int(
602                              GTK_SPIN_BUTTON(editable) );
603     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
604                                                       "config_option" );
605
606     g_hash_table_insert( hash_table, (gpointer)editable,
607                          (gpointer)p_config );
608 }
609
610 /****************************************************************************
611  * GtkStringChanged: signal called when the user changes a bool value.
612  ****************************************************************************/
613 static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data )
614 {
615     module_config_t *p_config;
616
617     GHashTable *hash_table;
618
619     hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
620                                                     "config_hash_table" );
621
622     /* free old p_config */
623     p_config = (module_config_t *)g_hash_table_lookup( hash_table,
624                                                        (gpointer)button );
625     if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, NULL );
626
627     p_config = malloc( sizeof(module_config_t) );
628     p_config->i_type = MODULE_CONFIG_ITEM_BOOL;
629     p_config->i_value = gtk_toggle_button_get_active( button );
630     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button),
631                                                       "config_option" );
632
633     g_hash_table_insert( hash_table, (gpointer)button,
634                          (gpointer)p_config );
635 }
636
637 /****************************************************************************
638  * GtkFreeHashTable: signal called when the config hash table is destroyed.
639  ****************************************************************************/
640 static void GtkFreeHashTable( gpointer user_data )
641 {
642     GHashTable *hash_table = (GHashTable *)user_data;
643
644     g_hash_table_foreach( hash_table, GtkFreeHashValue, NULL );
645     g_hash_table_destroy( hash_table );
646 }
647
648 /****************************************************************************
649  * GtkFreeHashValue: signal called when an element of the config hash table
650  * is destroyed.
651  ****************************************************************************/
652 static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data)
653 {
654     module_config_t *p_config = (module_config_t *)value;
655
656     if( p_config->i_type == MODULE_CONFIG_ITEM_STRING )
657         g_free( p_config->psz_value );
658     free( p_config );
659 }
660
661 /****************************************************************************
662  * GtkSaveHashValue: callback used when enumerating the hash table in
663  * GtkConfigApply().
664  ****************************************************************************/
665 static void GtkSaveHashValue( gpointer key, gpointer value, gpointer user_data)
666 {
667     module_config_t *p_config = (module_config_t *)value;
668
669     switch( p_config->i_type )
670     {
671
672     case MODULE_CONFIG_ITEM_STRING:
673     case MODULE_CONFIG_ITEM_FILE:
674     case MODULE_CONFIG_ITEM_PLUGIN:
675         config_PutPszVariable( p_config->psz_name, p_config->psz_value );
676         break;
677     case MODULE_CONFIG_ITEM_INTEGER:
678     case MODULE_CONFIG_ITEM_BOOL:
679         config_PutIntVariable( p_config->psz_name, p_config->i_value );
680         break;
681     }
682 }
683
684 /****************************************************************************
685  * GtkConfigDialogDestroyed: callback triggered when the config dialog box is
686  * destroyed.
687  ****************************************************************************/
688 static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data )
689 {
690     intf_thread_t *p_intf = (intf_thread_t *)user_data;
691     char *psz_module_name;
692
693     psz_module_name = gtk_object_get_data( object, "psz_module_name" );
694
695     /* remove the ref to the dialog box */
696     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
697                          psz_module_name, NULL );
698
699 }