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.35 2002/07/31 20:56:51 sam Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
8 * Loïc Minier <lool@via.ecp.fr>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble: Our main job is to build a nice interface from the modules config
27 * structure. Once this is done, we need to track each change made by the
28 * user to the data contained in this interface so that when/if he decides to
29 * apply his changes we can quickly commit them into the modules config
30 * structure. (for this last task we use a GHashTable to accumulate the
31 * changes. To commit them, we then just have to circle through it )
33 *****************************************************************************/
34 #include <sys/types.h> /* off_t */
40 #ifdef MODULE_NAME_IS_gnome
48 #include "gtk_support.h"
49 #include "gtk_common.h"
50 #include "gtk_preferences.h"
53 static void GtkCreateConfigDialog( char *, intf_thread_t * );
55 static void GtkConfigOk ( GtkButton *, gpointer );
56 static void GtkConfigApply ( GtkButton *, gpointer );
57 static void GtkConfigCancel ( GtkButton *, gpointer );
58 static void GtkConfigSave ( GtkButton *, gpointer );
60 static void GtkConfigDialogDestroyed ( GtkObject *, gpointer );
62 static void GtkStringChanged ( GtkEditable *, gpointer );
63 static void GtkIntChanged ( GtkEditable *, gpointer );
64 static void GtkFloatChanged ( GtkEditable *, gpointer );
65 static void GtkBoolChanged ( GtkToggleButton *, gpointer );
67 static void GtkFreeHashTable ( GtkObject *object );
68 static void GtkFreeHashValue ( gpointer, gpointer, gpointer );
69 static gboolean GtkSaveHashValue ( gpointer, gpointer, gpointer );
71 static void GtkModuleConfigure ( GtkButton *, gpointer );
72 static void GtkModuleSelected ( GtkButton *, gpointer );
73 static void GtkModuleHighlighted ( GtkCList *, int, int, GdkEventButton *,
76 /****************************************************************************
77 * Callback for menuitems: display configuration interface window
78 ****************************************************************************/
79 void GtkPreferencesShow( GtkMenuItem * menuitem, gpointer user_data )
81 intf_thread_t * p_intf;
83 p_intf = GtkGetIntf( menuitem );
85 GtkCreateConfigDialog( "main", p_intf );
88 /****************************************************************************
89 * GtkCreateConfigDialog: dynamically creates the configuration dialog
90 * box from all the configuration data provided by the selected module.
91 ****************************************************************************/
93 /* create a new tooltipped area */
94 #define TOOLTIP( text ) \
95 /* create an event box to catch some events */ \
96 item_event_box = gtk_event_box_new(); \
97 /* add a tooltip on mouseover */ \
98 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips, \
99 item_event_box, text, "" ); \
100 gtk_container_set_border_width( GTK_CONTAINER(item_event_box), 4 );
102 /* draws a right aligned label in side of a widget */
103 #define LABEL_AND_WIDGET( label_text, widget, tooltip ) \
104 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 ); \
105 item_align = gtk_alignment_new( 1, .5, 0, 0 ); \
106 item_label = gtk_label_new( label_text ); \
107 gtk_container_add( GTK_CONTAINER(item_align), item_label ); \
108 gtk_table_attach_defaults( GTK_TABLE(category_table), item_align, \
109 0, 1, rows - 1, rows ); \
110 item_align = gtk_alignment_new( 0, .5, .5, 0 ); \
111 gtk_container_add( GTK_CONTAINER(item_align), widget ); \
113 gtk_container_add( GTK_CONTAINER(item_event_box), item_align ); \
114 gtk_table_attach_defaults( GTK_TABLE(category_table), item_event_box, \
115 1, 2, rows - 1, rows );
117 static void GtkCreateConfigDialog( char *psz_module_name,
118 intf_thread_t *p_intf )
120 module_t *p_module, *p_module_bis;
121 module_config_t *p_item;
125 GHashTable *config_hash_table;
127 GtkWidget *item_event_box;
129 GtkWidget *config_dialog;
130 GtkWidget *config_dialog_vbox;
131 GtkWidget *config_notebook;
133 GtkWidget *category_table = NULL;
134 GtkWidget *category_label = NULL;
136 #ifndef MODULE_NAME_IS_gnome
137 GtkWidget *dialog_action_area;
140 GtkWidget *ok_button;
141 GtkWidget *apply_button;
142 GtkWidget *save_button;
143 GtkWidget *cancel_button;
145 GtkWidget *item_align;
146 GtkWidget *item_frame;
147 GtkWidget *item_hbox;
148 GtkWidget *item_label;
149 GtkWidget *item_vbox;
150 GtkWidget *item_combo;
151 GtkWidget *string_entry;
152 GtkWidget *integer_spinbutton;
153 GtkWidget *float_spinbutton;
155 GtkWidget *bool_checkbutton;
156 GtkWidget *module_clist;
157 GtkWidget *module_config_button;
158 GtkWidget *module_select_button;
160 gint category_max_height;
162 /* Check if the dialog box is already opened because we don't want to
163 * duplicate identical dialog windows. */
164 config_dialog = (GtkWidget *)gtk_object_get_data(
165 GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name );
168 /* Yeah it was open */
169 gtk_widget_grab_focus( config_dialog );
174 /* Look for the selected module */
175 for( p_module = p_intf->p_vlc->p_module_bank->first ; p_module != NULL ;
176 p_module = p_module->next )
180 && !strcmp( psz_module_name, p_module->psz_object_name ) )
185 if( !p_module ) return;
187 /* We found it, now we can start building its configuration interface */
188 /* Create the configuration dialog box */
190 #ifdef MODULE_NAME_IS_gnome
191 config_dialog = gnome_dialog_new( p_module->psz_longname, NULL );
192 config_dialog_vbox = GNOME_DIALOG(config_dialog)->vbox;
194 config_dialog = gtk_dialog_new();
195 gtk_window_set_title( GTK_WINDOW(config_dialog), p_module->psz_longname );
196 config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox;
199 gtk_object_set_data( GTK_OBJECT(config_dialog), "p_intf", p_intf );
201 category_max_height = config_GetInt( p_intf, MODULE_STRING "-prefs-maxh" );
203 gtk_window_set_policy( GTK_WINDOW(config_dialog), TRUE, TRUE, FALSE );
204 gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 );
206 /* Create our config hash table and associate it with the dialog box */
207 config_hash_table = g_hash_table_new( NULL, NULL );
208 gtk_object_set_data( GTK_OBJECT(config_dialog),
209 "config_hash_table", config_hash_table );
211 /* Create notebook */
212 config_notebook = gtk_notebook_new();
213 gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE );
214 gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook );
216 /* Enumerate config options and add corresponding config boxes */
217 p_item = p_module->p_config;
220 switch( p_item->i_type )
223 case CONFIG_HINT_CATEGORY:
224 case CONFIG_HINT_END:
227 * Before we start building the interface for the new category, we
228 * must close/finish the previous one we were generating.
232 GtkWidget *_scrolled_window;
233 GtkWidget *_viewport;
235 GtkRequisition _requisition;
237 /* create a vbox to deal with EXPAND/FILL issues in the
238 * notebook page, and pack it with the previously generated
240 _vbox = gtk_vbox_new( FALSE, 0 );
241 gtk_container_set_border_width( GTK_CONTAINER(_vbox), 4 );
242 gtk_box_pack_start( GTK_BOX(_vbox), category_table,
245 /* create a new scrolled window that will contain all of the
247 _scrolled_window = gtk_scrolled_window_new( NULL, NULL );
248 gtk_scrolled_window_set_policy(
249 GTK_SCROLLED_WINDOW(_scrolled_window), GTK_POLICY_NEVER,
250 GTK_POLICY_AUTOMATIC );
251 /* add scrolled window as a notebook page */
252 gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook),
253 _scrolled_window, category_label );
254 /* pack the vbox into the scrolled window */
255 _viewport = gtk_viewport_new( NULL, NULL );
256 gtk_viewport_set_shadow_type( GTK_VIEWPORT(_viewport),
258 gtk_container_add( GTK_CONTAINER(_viewport), _vbox );
259 gtk_container_add( GTK_CONTAINER(_scrolled_window),
262 /* set the size of the scrolled window to the size of the
264 gtk_widget_show_all( _vbox );
265 gtk_widget_size_request( _vbox, &_requisition );
266 if( _requisition.height > category_max_height )
267 gtk_widget_set_usize( _scrolled_window, -1,
268 category_max_height );
270 gtk_widget_set_usize( _scrolled_window, -1,
271 _requisition.height );
276 * Now we can start taking care of the new category
279 if( p_item->i_type == CONFIG_HINT_CATEGORY )
281 /* create a new table for right-left alignment of children */
282 category_table = gtk_table_new( 0, 0, FALSE );
283 gtk_table_set_col_spacings( GTK_TABLE(category_table), 4 );
286 /* create a new category label */
287 category_label = gtk_label_new( p_item->psz_text );
292 case CONFIG_ITEM_MODULE:
294 item_frame = gtk_frame_new( p_item->psz_text );
296 gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 );
297 gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame,
298 0, 2, rows - 1, rows );
300 item_vbox = gtk_vbox_new( FALSE, 4 );
301 gtk_container_add( GTK_CONTAINER(item_frame), item_vbox );
303 /* create a new clist widget */
305 gchar * titles[] = { _("Name"), _("Description") };
307 module_clist = gtk_clist_new_with_titles( 2, titles );
309 gtk_object_set_data( GTK_OBJECT(module_clist), "p_intf", p_intf );
310 gtk_clist_column_titles_passive( GTK_CLIST(module_clist) );
311 gtk_clist_set_selection_mode( GTK_CLIST(module_clist),
312 GTK_SELECTION_SINGLE);
313 gtk_container_add( GTK_CONTAINER(item_vbox), module_clist );
315 /* build a list of available modules */
318 char * psz_capability;
320 for( p_module_bis = p_intf->p_vlc->p_module_bank->first ;
321 p_module_bis != NULL ;
322 p_module_bis = p_module_bis->next )
325 for( psz_capability = p_module_bis->pp_capabilities[0] ;
329 if( !strcmp( psz_capability, p_item->psz_type ) )
331 entry[0] = p_module_bis->psz_object_name;
332 entry[1] = p_module_bis->psz_longname;
333 gtk_clist_append( GTK_CLIST(module_clist), entry );
341 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
343 gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist),
346 /* connect signals to the modules list */
347 gtk_signal_connect( GTK_OBJECT(module_clist), "select_row",
348 GTK_SIGNAL_FUNC(GtkModuleHighlighted),
351 /* hbox holding the "select" and "configure" buttons */
352 item_hbox = gtk_hbox_new( FALSE, 4 );
353 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
355 /* add configure button */
356 module_config_button =
357 gtk_button_new_with_label( _("Configure") );
358 gtk_widget_set_sensitive( module_config_button, FALSE );
359 gtk_container_add( GTK_CONTAINER(item_hbox),
360 module_config_button );
361 gtk_object_set_data( GTK_OBJECT(module_config_button),
363 gtk_object_set_data( GTK_OBJECT(module_clist),
364 "config_button", module_config_button );
366 /* add select button */
367 module_select_button =
368 gtk_button_new_with_label( _("Select") );
369 gtk_container_add( GTK_CONTAINER(item_hbox),
370 module_select_button );
371 /* add a tooltip on mouseover */
372 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
373 module_select_button,
374 p_item->psz_longtext, "" );
376 /* hbox holding the "selected" label and text input */
377 item_hbox = gtk_hbox_new( FALSE, 4 );
378 gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox);
380 item_label = gtk_label_new( _("Selected:") );
381 gtk_container_add( GTK_CONTAINER(item_hbox), item_label );
383 /* add input box with default value */
384 string_entry = gtk_entry_new();
385 gtk_object_set_data( GTK_OBJECT(module_clist),
386 "module_entry", string_entry );
387 gtk_container_add( GTK_CONTAINER(item_hbox), string_entry );
388 vlc_mutex_lock( p_item->p_lock );
389 gtk_entry_set_text( GTK_ENTRY(string_entry),
390 p_item->psz_value ? p_item->psz_value : "" );
391 vlc_mutex_unlock( p_item->p_lock );
392 /* add a tooltip on mouseover */
393 gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips,
394 string_entry, p_item->psz_longtext, "" );
396 /* connect signals to the buttons */
397 gtk_signal_connect( GTK_OBJECT(module_config_button), "clicked",
398 GTK_SIGNAL_FUNC(GtkModuleConfigure),
399 (gpointer)module_clist );
400 gtk_signal_connect( GTK_OBJECT(module_select_button), "clicked",
401 GTK_SIGNAL_FUNC(GtkModuleSelected),
402 (gpointer)module_clist );
404 /* connect signal to track changes in the text box */
405 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
407 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
408 GTK_SIGNAL_FUNC(GtkStringChanged),
409 (gpointer)config_dialog );
412 case CONFIG_ITEM_STRING:
413 case CONFIG_ITEM_FILE:
415 if( !p_item->ppsz_list )
417 /* add input box with default value */
418 item_combo = string_entry = gtk_entry_new();
422 /* add combo box with default value */
426 for( i=0; p_item->ppsz_list[i]; i++ )
427 items = g_list_append( items, p_item->ppsz_list[i] );
429 item_combo = gtk_combo_new();
430 string_entry = GTK_COMBO(item_combo)->entry;
431 gtk_combo_set_popdown_strings( GTK_COMBO(item_combo),
436 vlc_mutex_lock( p_item->p_lock );
437 gtk_entry_set_text( GTK_ENTRY(string_entry),
438 p_item->psz_value ? p_item->psz_value : "" );
439 vlc_mutex_unlock( p_item->p_lock );
441 /* connect signal to track changes in the text box */
442 gtk_object_set_data( GTK_OBJECT(string_entry), "config_option",
444 gtk_signal_connect( GTK_OBJECT(string_entry), "changed",
445 GTK_SIGNAL_FUNC(GtkStringChanged),
446 (gpointer)config_dialog );
448 LABEL_AND_WIDGET( p_item->psz_text,
449 item_combo, p_item->psz_longtext );
452 case CONFIG_ITEM_INTEGER:
454 /* add input box with default value */
455 item_adj = gtk_adjustment_new( p_item->i_value,
456 -1, 99999, 1, 10, 10 );
457 integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
460 /* connect signal to track changes in the spinbutton value */
461 gtk_object_set_data( GTK_OBJECT(integer_spinbutton),
462 "config_option", p_item->psz_name );
463 gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed",
464 GTK_SIGNAL_FUNC(GtkIntChanged),
465 (gpointer)config_dialog );
467 LABEL_AND_WIDGET( p_item->psz_text,
468 integer_spinbutton, p_item->psz_longtext );
471 case CONFIG_ITEM_FLOAT:
473 /* add input box with default value */
474 item_adj = gtk_adjustment_new( p_item->f_value,
475 0, 99999, 0.01, 10, 10 );
476 float_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj),
479 /* connect signal to track changes in the spinbutton value */
480 gtk_object_set_data( GTK_OBJECT(float_spinbutton),
481 "config_option", p_item->psz_name );
482 gtk_signal_connect( GTK_OBJECT(float_spinbutton), "changed",
483 GTK_SIGNAL_FUNC(GtkFloatChanged),
484 (gpointer)config_dialog );
486 LABEL_AND_WIDGET( p_item->psz_text,
487 float_spinbutton, p_item->psz_longtext );
490 case CONFIG_ITEM_BOOL:
492 /* add check button */
493 bool_checkbutton = gtk_check_button_new();
494 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton),
497 /* connect signal to track changes in the button state */
498 gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option",
500 gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled",
501 GTK_SIGNAL_FUNC(GtkBoolChanged),
502 (gpointer)config_dialog );
504 LABEL_AND_WIDGET( p_item->psz_text,
505 bool_checkbutton, p_item->psz_longtext );
511 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
513 #ifndef MODULE_NAME_IS_gnome
514 /* Now let's add the action buttons at the bottom of the page */
515 dialog_action_area = GTK_DIALOG(config_dialog)->action_area;
516 gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 );
518 /* add a new table for the config option */
519 item_hbox = gtk_hbox_new( FALSE, 0 );
520 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
522 item_hbox = gtk_hbox_new( FALSE, 0 );
523 gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox,
527 /* Create the OK button */
528 #ifdef MODULE_NAME_IS_gnome
529 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
530 GNOME_STOCK_BUTTON_OK );
532 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
534 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
535 GNOME_STOCK_BUTTON_APPLY );
537 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
539 gnome_dialog_append_button_with_pixmap(
540 GNOME_DIALOG(config_dialog), _("Save"), GNOME_STOCK_PIXMAP_SAVE );
542 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
544 gnome_dialog_append_button( GNOME_DIALOG(config_dialog),
545 GNOME_STOCK_BUTTON_CANCEL );
547 GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data);
549 ok_button = gtk_button_new_with_label( _("OK") );
550 gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button,
553 apply_button = gtk_button_new_with_label( _("Apply") );
554 gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button,
557 save_button = gtk_button_new_with_label( _("Save") );
558 gtk_box_pack_start( GTK_BOX(dialog_action_area), save_button,
561 cancel_button = gtk_button_new_with_label( _("Cancel") );
562 gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button,
566 gtk_signal_connect( GTK_OBJECT(ok_button), "clicked",
567 GTK_SIGNAL_FUNC(GtkConfigOk),
569 gtk_widget_set_sensitive( apply_button, FALSE );
570 gtk_object_set_data( GTK_OBJECT(config_dialog), "apply_button",
572 gtk_signal_connect( GTK_OBJECT(apply_button), "clicked",
573 GTK_SIGNAL_FUNC(GtkConfigApply),
575 gtk_signal_connect( GTK_OBJECT(save_button), "clicked",
576 GTK_SIGNAL_FUNC(GtkConfigSave),
578 gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked",
579 GTK_SIGNAL_FUNC(GtkConfigCancel),
584 /* Ok, job done successfully. Let's keep a reference to the dialog box */
585 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
586 psz_module_name, config_dialog );
587 gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name",
590 /* we want this ref to be destroyed if the object is destroyed */
591 gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy",
592 GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed),
595 gtk_widget_show_all( config_dialog );
598 #undef LABEL_AND_WIDGET
601 /****************************************************************************
602 * GtkConfigApply: store the changes to the config inside the modules
603 * configuration structure and clear the hash table.
604 ****************************************************************************/
605 void GtkConfigApply( GtkButton * button, gpointer user_data )
607 intf_thread_t *p_intf;
608 GHashTable *hash_table;
609 GtkWidget *apply_button;
611 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
612 "config_hash_table" );
613 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
615 g_hash_table_foreach_remove( hash_table, GtkSaveHashValue, (void*)p_intf );
617 /* change the highlight status of the Apply button */
618 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
620 gtk_widget_set_sensitive( apply_button, FALSE );
623 void GtkConfigOk( GtkButton * button, gpointer user_data )
625 GtkConfigApply( button, user_data );
626 gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
630 void GtkConfigCancel( GtkButton * button, gpointer user_data )
632 gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
635 void GtkConfigSave( GtkButton * button, gpointer user_data )
637 intf_thread_t *p_intf;
639 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data),
641 GtkConfigApply( button, user_data );
642 config_SaveConfigFile( p_intf, NULL );
645 /****************************************************************************
646 * GtkModuleHighlighted: display module description when an entry is selected
647 * in the clist, and activate the configure button if necessary.
648 ****************************************************************************/
649 void GtkModuleHighlighted( GtkCList *module_clist, int row, int column,
650 GdkEventButton *event, gpointer user_data )
652 intf_thread_t *p_intf;
653 GtkWidget *config_button;
657 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(module_clist),
660 if( gtk_clist_get_text( GTK_CLIST(module_clist), row, 0, &psz_name ) )
662 /* look for module 'psz_name' */
663 for( p_module = p_intf->p_vlc->p_module_bank->first ;
665 p_module = p_module->next )
667 if( !strcmp( p_module->psz_object_name, psz_name ) )
669 gtk_object_set_data( GTK_OBJECT(module_clist),
670 "module_highlighted", p_module );
671 config_button = gtk_object_get_data( GTK_OBJECT(module_clist),
673 if( p_module->i_config_items )
674 gtk_widget_set_sensitive( config_button, TRUE );
676 gtk_widget_set_sensitive( config_button, FALSE );
685 /****************************************************************************
686 * GtkModuleConfigure: display module configuration dialog box.
687 ****************************************************************************/
688 void GtkModuleConfigure( GtkButton *button, gpointer user_data )
691 intf_thread_t *p_intf;
693 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
694 "module_highlighted" );
696 if( !p_module ) return;
697 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
699 GtkCreateConfigDialog( p_module->psz_object_name, (gpointer)p_intf );
703 /****************************************************************************
704 * GtkModuleSelected: select module.
705 ****************************************************************************/
706 void GtkModuleSelected( GtkButton *button, gpointer user_data )
711 p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data),
712 "module_highlighted" );
713 widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
715 if( !p_module ) return;
717 gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_object_name );
721 /****************************************************************************
722 * GtkStringChanged: signal called when the user changes a string value.
723 ****************************************************************************/
724 static void GtkStringChanged( GtkEditable *editable, gpointer user_data )
726 intf_thread_t *p_intf;
727 module_config_t *p_config;
728 GHashTable *hash_table;
729 GtkWidget *apply_button;
731 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
733 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
734 "config_hash_table" );
735 /* free old p_config */
736 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
737 (gpointer)editable );
738 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
740 p_config = malloc( sizeof(module_config_t) );
741 p_config->i_type = CONFIG_ITEM_STRING;
742 p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 );
743 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
746 g_hash_table_insert( hash_table, (gpointer)editable,
747 (gpointer)p_config );
749 /* change the highlight status of the Apply button */
750 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
752 gtk_widget_set_sensitive( apply_button, TRUE );
755 /****************************************************************************
756 * GtkIntChanged: signal called when the user changes an integer value.
757 ****************************************************************************/
758 static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
760 intf_thread_t *p_intf;
761 module_config_t *p_config;
762 GHashTable *hash_table;
763 GtkWidget *apply_button;
765 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
767 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
769 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
770 "config_hash_table" );
772 /* free old p_config */
773 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
774 (gpointer)editable );
775 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
777 p_config = malloc( sizeof(module_config_t) );
778 p_config->i_type = CONFIG_ITEM_INTEGER;
779 p_config->i_value = gtk_spin_button_get_value_as_int(
780 GTK_SPIN_BUTTON(editable) );
781 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
784 g_hash_table_insert( hash_table, (gpointer)editable,
785 (gpointer)p_config );
787 /* change the highlight status of the Apply button */
788 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
790 gtk_widget_set_sensitive( apply_button, TRUE );
793 /****************************************************************************
794 * GtkFloatChanged: signal called when the user changes a float value.
795 ****************************************************************************/
796 static void GtkFloatChanged( GtkEditable *editable, gpointer user_data )
798 intf_thread_t *p_intf;
799 module_config_t *p_config;
800 GHashTable *hash_table;
801 GtkWidget *apply_button;
803 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable),
805 gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
807 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
808 "config_hash_table" );
810 /* free old p_config */
811 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
812 (gpointer)editable );
813 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
815 p_config = malloc( sizeof(module_config_t) );
816 p_config->i_type = CONFIG_ITEM_FLOAT;
817 p_config->f_value = gtk_spin_button_get_value_as_float(
818 GTK_SPIN_BUTTON(editable) );
819 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
822 g_hash_table_insert( hash_table, (gpointer)editable,
823 (gpointer)p_config );
825 /* change the highlight status of the Apply button */
826 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
828 gtk_widget_set_sensitive( apply_button, TRUE );
831 /****************************************************************************
832 * GtkBoolChanged: signal called when the user changes a bool value.
833 ****************************************************************************/
834 static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data )
836 intf_thread_t *p_intf;
837 module_config_t *p_config;
838 GHashTable *hash_table;
839 GtkWidget *apply_button;
841 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button),
843 hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data),
844 "config_hash_table" );
846 /* free old p_config */
847 p_config = (module_config_t *)g_hash_table_lookup( hash_table,
849 if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf );
851 p_config = malloc( sizeof(module_config_t) );
852 p_config->i_type = CONFIG_ITEM_BOOL;
853 p_config->i_value = gtk_toggle_button_get_active( button );
854 p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button),
857 g_hash_table_insert( hash_table, (gpointer)button,
858 (gpointer)p_config );
860 /* change the highlight status of the Apply button */
861 apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data),
863 gtk_widget_set_sensitive( apply_button, TRUE );
866 /****************************************************************************
867 * GtkFreeHashTable: signal called when the config hash table is destroyed.
868 ****************************************************************************/
869 static void GtkFreeHashTable( GtkObject *object )
871 GHashTable *hash_table = (GHashTable *)gtk_object_get_data( object,
872 "config_hash_table" );
873 intf_thread_t *p_intf = (intf_thread_t *)gtk_object_get_data( object,
876 g_hash_table_foreach( hash_table, GtkFreeHashValue, (void *)p_intf );
877 g_hash_table_destroy( hash_table );
880 /****************************************************************************
881 * GtkFreeHashValue: signal called when an element of the config hash table
883 ****************************************************************************/
884 static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data)
886 module_config_t * p_config = (module_config_t *)value;
888 if( p_config->i_type == CONFIG_ITEM_STRING )
889 if( p_config->psz_value ) g_free( p_config->psz_value );
893 /****************************************************************************
894 * GtkSaveHashValue: callback used when enumerating the hash table in
896 ****************************************************************************/
897 static gboolean GtkSaveHashValue( gpointer key, gpointer value,
900 intf_thread_t * p_intf = (intf_thread_t *)user_data;
901 module_config_t * p_config = (module_config_t *)value;
903 switch( p_config->i_type )
906 case CONFIG_ITEM_STRING:
907 case CONFIG_ITEM_FILE:
908 case CONFIG_ITEM_MODULE:
909 config_PutPsz( p_intf, p_config->psz_name,
910 *p_config->psz_value ? p_config->psz_value : NULL );
912 case CONFIG_ITEM_INTEGER:
913 case CONFIG_ITEM_BOOL:
914 config_PutInt( p_intf, p_config->psz_name, p_config->i_value );
916 case CONFIG_ITEM_FLOAT:
917 config_PutFloat( p_intf, p_config->psz_name, p_config->f_value );
921 /* free the hash value we allocated */
922 if( p_config->i_type == CONFIG_ITEM_STRING )
923 g_free( p_config->psz_value );
926 /* return TRUE so glib will free the hash entry */
930 /****************************************************************************
931 * GtkConfigDialogDestroyed: callback triggered when the config dialog box is
933 ****************************************************************************/
934 static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data )
936 intf_thread_t *p_intf = (intf_thread_t *)user_data;
937 char *psz_module_name;
939 psz_module_name = gtk_object_get_data( object, "psz_module_name" );
941 /* remove the ref to the dialog box */
942 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
943 psz_module_name, NULL );
945 GtkFreeHashTable( object );