2 * Copyright © 2000-2003 Marco Pesenti Gritti
3 * Copyright © 2003, 2004 Christian Persch
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "ephy-dialog.h"
25 #include "ephy-state.h"
27 #include "eel-gconf-extensions.h"
28 #include "ephy-debug.h"
32 #include <gtk/gtktogglebutton.h>
33 #include <gtk/gtkradiobutton.h>
34 #include <gtk/gtkcombobox.h>
35 #include <gtk/gtkspinbutton.h>
36 #include <gtk/gtkeditable.h>
37 #include <gtk/gtkentry.h>
38 #include <gtk/gtksizegroup.h>
39 #include <gtk/gtkdialog.h>
40 #include <glade/glade-xml.h>
47 PROP_PERSIST_POSITION,
67 EphyDialogApplyType apply_type;
69 WidgetType widget_type;
77 #define EPHY_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_DIALOG, EphyDialogPrivate))
79 struct _EphyDialogPrivate
88 guint has_default_size : 1;
90 guint initialized : 1;
91 guint persist_position : 1;
96 #define SPIN_DELAY 0.20
104 static guint signals [LAST_SIGNAL] = { 0, };
106 static void ephy_dialog_class_init (EphyDialogClass *klass);
107 static void ephy_dialog_init (EphyDialog *window);
109 static GObjectClass *parent_class = NULL;
112 ephy_dialog_get_type (void)
114 static GType type = 0;
116 if (G_UNLIKELY (type == 0))
118 const GTypeInfo our_info =
120 sizeof (EphyDialogClass),
121 NULL, /* base_init */
122 NULL, /* base_finalize */
123 (GClassInitFunc) ephy_dialog_class_init,
125 NULL, /* class_data */
128 (GInstanceInitFunc) ephy_dialog_init
131 type = g_type_register_static (G_TYPE_OBJECT,
139 static PropertyInfo *
140 lookup_info (EphyDialog *dialog, const char *id)
142 return g_hash_table_lookup (dialog->priv->props, id);
146 set_sensitivity (PropertyInfo *info, gboolean sensitive)
148 g_return_if_fail (info->widget != NULL);
150 if (info->widget_type == PT_RADIOBUTTON)
154 list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (info->widget));
156 for (l = list; l != NULL; l = l->next)
158 gtk_widget_set_sensitive (GTK_WIDGET (l->data), sensitive);
161 else if (info->widget_type == PT_EDITABLE)
163 gtk_editable_set_editable (GTK_EDITABLE (info->widget), sensitive);
167 gtk_widget_set_sensitive (info->widget, sensitive);
172 set_value_from_pref (PropertyInfo *info, GValue *value)
176 switch (info->data_type)
179 g_value_init (value, G_TYPE_STRING);
180 text = eel_gconf_get_string (info->pref);
181 g_value_take_string (value, text);
184 g_value_init (value, G_TYPE_INT);
185 g_value_set_int (value, eel_gconf_get_integer (info->pref));
188 g_value_init (value, G_TYPE_FLOAT);
189 g_value_set_float (value, eel_gconf_get_float (info->pref));
192 g_value_init (value, G_TYPE_BOOLEAN);
193 g_value_set_boolean (value, eel_gconf_get_boolean (info->pref));
196 g_warning ("Unsupported value read from pref %s\n", info->pref);
202 set_pref_from_value (PropertyInfo *info, GValue *value)
204 const char *pref = info->pref;
206 if (!G_VALUE_HOLDS (value, info->data_type))
208 g_warning ("Value type mismatch for id[%s], pref[%s]", info->id, info->pref);
212 switch (info->data_type)
216 const char *string = g_value_get_string (value);
219 eel_gconf_set_string (pref, string);
223 eel_gconf_unset_key (pref);
228 eel_gconf_set_integer (pref, g_value_get_int (value));
231 eel_gconf_set_float (pref, g_value_get_float (value));
234 eel_gconf_set_boolean (pref, g_value_get_boolean (value));
242 set_value_from_editable (PropertyInfo *info, GValue *value)
245 gboolean retval = TRUE;
246 gboolean free_text = TRUE;
248 g_return_val_if_fail (GTK_IS_EDITABLE (info->widget), FALSE);
250 text = gtk_editable_get_chars (GTK_EDITABLE (info->widget), 0, -1);
252 g_value_init (value, info->data_type);
253 switch (info->data_type)
256 g_value_take_string (value, text);
259 /* FIXME : handle possible errors in the input for int and float */
261 g_value_set_int (value, atoi (text));
264 g_value_set_float (value, strtod (text, NULL));
268 g_value_unset (value);
269 g_warning ("Unsupported value type for editable %s", info->id);
282 set_value_from_combobox (PropertyInfo *info, GValue *value)
284 g_return_val_if_fail (GTK_IS_COMBO_BOX (info->widget), FALSE);
286 if (info->data_col != -1)
291 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (info->widget), &iter))
293 model = gtk_combo_box_get_model (GTK_COMBO_BOX (info->widget));
294 gtk_tree_model_get_value (model, &iter, info->data_col, value);
299 else if (info->data_type == G_TYPE_INT)
303 index = gtk_combo_box_get_active (GTK_COMBO_BOX (info->widget));
307 g_value_init (value, G_TYPE_INT);
308 g_value_set_int (value, index);
315 g_warning ("Unsupported data type for combo %s\n", info->id);
322 get_radio_button_active_index (GtkWidget *radiobutton)
324 GtkToggleButton *toggle_button;
326 int index, i, length;
329 list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton));
330 length = g_slist_length (list);
332 /* iterate over list to find active button */
333 for (i = 0; list != NULL; i++, list = list->next)
335 /* get button and text */
336 toggle_button = GTK_TOGGLE_BUTTON (list->data);
337 if (gtk_toggle_button_get_active (toggle_button))
343 /* check we didn't run off end */
344 g_assert (list != NULL);
346 /* return index (reverse order!) */
347 return index = (length - 1) - i;
351 set_value_from_radiobuttongroup (PropertyInfo *info, GValue *value)
353 gboolean retval = TRUE;
356 g_return_val_if_fail (GTK_IS_RADIO_BUTTON (info->widget), FALSE);
358 index = get_radio_button_active_index (info->widget);
359 g_return_val_if_fail (index >= 0, FALSE);
361 if (info->data_type == G_TYPE_STRING)
363 g_return_val_if_fail (info->string_enum != NULL, FALSE);
364 g_return_val_if_fail (g_list_nth_data (info->string_enum, index) != NULL, FALSE);
366 g_value_init (value, G_TYPE_STRING);
367 g_value_set_string (value, (char*) g_list_nth_data (info->string_enum, index));
369 else if (info->data_type == G_TYPE_INT)
371 g_value_init (value, G_TYPE_INT);
372 g_value_set_int (value, index);
377 g_warning ("unsupported data type for radio button %s\n", info->id);
384 set_value_from_spin_button (PropertyInfo *info, GValue *value)
386 gboolean retval = TRUE;
390 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (info->widget), FALSE);
392 f = gtk_spin_button_get_value (GTK_SPIN_BUTTON (info->widget));
394 is_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(info->widget)) == 0);
396 if (info->data_type == G_TYPE_INT && is_int)
398 g_value_init (value, G_TYPE_INT);
399 g_value_set_int (value, (int) f);
401 else if (info->data_type == G_TYPE_FLOAT)
403 g_value_init (value, G_TYPE_FLOAT);
404 g_value_set_float (value, f);
409 g_warning ("Unsupported data type for spin button %s\n", info->id);
416 set_value_from_togglebutton (PropertyInfo *info, GValue *value)
418 gboolean retval = TRUE;
421 g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (info->widget), FALSE);
423 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (info->widget));
425 if (info->apply_type & PT_INVERTED)
430 if (info->data_type == G_TYPE_BOOLEAN)
432 g_value_init (value, info->data_type);
433 g_value_set_boolean (value, active);
438 g_warning ("Unsupported data type for toggle button %s\n", info->id);
445 set_value_from_info (PropertyInfo *info, GValue *value)
449 if (info->sane_state == FALSE)
454 switch (info->widget_type)
457 retval = set_value_from_spin_button (info, value);
460 retval = set_value_from_radiobuttongroup (info, value);
462 case PT_TOGGLEBUTTON:
463 retval = set_value_from_togglebutton (info, value);
466 retval = set_value_from_editable (info, value);
469 retval = set_value_from_combobox (info, value);
473 g_warning ("Unsupported widget type\n");
481 set_editable_from_value (PropertyInfo *info, const GValue *value)
484 int pos = 0; /* insertion position */
486 g_return_if_fail (GTK_IS_EDITABLE (info->widget));
488 switch (info->data_type)
491 text = g_value_dup_string (value);
494 text = g_strdup_printf ("%d", g_value_get_int (value));
497 text = g_strdup_printf ("%.2f", g_value_get_float (value));
505 text = g_strdup ("");
508 info->sane_state = TRUE;
510 gtk_editable_delete_text (GTK_EDITABLE (info->widget), 0, -1);
511 gtk_editable_insert_text (GTK_EDITABLE (info->widget), text, strlen (text), &pos);
517 strcmp_with_null (const char *key1,
520 if (key1 == NULL && key2 == NULL)
533 return strcmp (key1, key2);
537 get_index_from_value (const GValue *value, GList *string_enum)
545 val = g_value_get_string (value);
547 s = g_list_find_custom (string_enum, val, (GCompareFunc) strcmp_with_null);
551 index = g_list_position (string_enum, s);
557 index = g_value_get_int (value);
564 compare_values (const GValue *a, const GValue *b)
566 if (G_VALUE_HOLDS (a, G_TYPE_STRING))
570 ta = g_value_get_string (a);
571 tb = g_value_get_string (b);
573 return (strcmp_with_null (ta, tb) == 0);
575 else if (G_VALUE_HOLDS (a, G_TYPE_INT))
577 return g_value_get_int (a) == g_value_get_int (b);
579 else if (G_VALUE_HOLDS (a, G_TYPE_FLOAT))
581 return g_value_get_float (a) == g_value_get_float (b);
583 else if (G_VALUE_HOLDS (a, G_TYPE_BOOLEAN))
585 return g_value_get_boolean (a) == g_value_get_boolean (b);
592 set_combo_box_from_value (PropertyInfo *info, const GValue *value)
594 g_return_if_fail (GTK_IS_COMBO_BOX (info->widget));
596 if (info->data_col != -1)
598 GValue data = { 0, };
601 gboolean valid, found = FALSE;
603 model = gtk_combo_box_get_model (GTK_COMBO_BOX (info->widget));
605 valid = gtk_tree_model_get_iter_first (model, &iter);
608 gtk_tree_model_get_value (model, &iter, info->data_col, &data);
609 found = compare_values (&data, value);
610 g_value_unset (&data);
614 valid = gtk_tree_model_iter_next (model, &iter);
619 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (info->widget), &iter);
623 gtk_combo_box_set_active (GTK_COMBO_BOX (info->widget), 0);
626 info->sane_state = found;
628 else if (info->data_type == G_TYPE_INT)
632 index = g_value_get_int (value);
634 info->sane_state = index >= 0;
636 g_return_if_fail (index >= -1);
638 gtk_combo_box_set_active (GTK_COMBO_BOX (info->widget), index);
642 g_warning ("Unsupported data type for combo box %s\n", info->id);
647 set_radiobuttongroup_from_value (PropertyInfo *info, const GValue *value)
649 GtkToggleButton *button;
654 g_return_if_fail (GTK_IS_RADIO_BUTTON (info->widget));
656 list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (info->widget));
658 length = g_slist_length (list);
660 index = get_index_from_value (value, info->string_enum);
662 /* new buttons are *prepended* to the list, so button added as first
663 * has last position in the list */
664 index = (length - 1) - index;
666 if (index < 0 || index >= length)
668 info->sane_state = FALSE;
669 g_return_if_fail (index >= 0 && index < length);
673 button = GTK_TOGGLE_BUTTON (g_slist_nth_data (list, index));
674 g_return_if_fail (button != NULL);
676 info->sane_state = TRUE;
678 if (gtk_toggle_button_get_active (button) == FALSE)
680 gtk_toggle_button_set_active (button, TRUE);
685 set_spin_button_from_value (PropertyInfo *info, const GValue *value)
690 g_return_if_fail (GTK_IS_SPIN_BUTTON (info->widget));
692 is_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON (info->widget)) == 0);
694 if (info->data_type == G_TYPE_INT && is_int)
696 f = (float) g_value_get_int (value);
698 else if (info->data_type == G_TYPE_FLOAT)
700 f = g_value_get_float (value);
704 info->sane_state = FALSE;
705 g_warning ("Unsupported data type for spin button %s\n", info->id);
709 info->sane_state = TRUE;
711 gtk_spin_button_set_value (GTK_SPIN_BUTTON (info->widget), f);
715 set_togglebutton_from_value (PropertyInfo *info, const GValue *value)
719 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (info->widget));
720 g_return_if_fail (info->data_type == G_TYPE_BOOLEAN);
722 active = g_value_get_boolean (value);
724 if (info->apply_type & PT_INVERTED)
729 info->sane_state = TRUE;
731 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->widget), active);
735 set_info_from_value (PropertyInfo *info, const GValue *value)
737 if (!G_VALUE_HOLDS (value, info->data_type))
739 g_warning ("Incompatible value types for id %s\n", info->id);
743 switch (info->widget_type)
746 set_spin_button_from_value (info, value);
749 set_radiobuttongroup_from_value (info, value);
751 case PT_TOGGLEBUTTON:
752 set_togglebutton_from_value (info, value);
755 set_editable_from_value (info, value);
758 set_combo_box_from_value (info, value);
761 g_warning ("Unknown widget type\n");
766 /* widget changed callbacks */
769 set_pref_from_info_and_emit (PropertyInfo *info)
771 GValue value = { 0, };
773 if (!set_value_from_info (info, &value))
778 g_signal_emit (info->dialog, signals[CHANGED], g_quark_from_string (info->id), &value);
780 if ((info->apply_type & PT_AUTOAPPLY) && info->pref != NULL)
782 set_pref_from_value (info, &value);
785 g_value_unset (&value);
789 togglebutton_clicked_cb (GtkWidget *widget, PropertyInfo *info)
791 info->sane_state = TRUE;
793 set_pref_from_info_and_emit (info);
797 radiobutton_clicked_cb (GtkWidget *widget, PropertyInfo *info)
799 info->sane_state = TRUE;
801 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)))
806 set_pref_from_info_and_emit (info);
810 spinbutton_timeout_cb (PropertyInfo *info)
814 spin_timer = (GTimer *) g_object_get_data (G_OBJECT (info->widget), "timer");
816 /* timer still valid? */
817 if (spin_timer == NULL)
819 /* don't call me again */
823 /* okay, we're ready to set */
824 if (g_timer_elapsed (spin_timer, NULL) >= SPIN_DELAY)
826 /* kill off the timer */
827 g_timer_destroy (spin_timer);
828 g_object_set_data (G_OBJECT (info->widget), "timer", NULL);
830 /* HACK update the spinbutton here so that the
831 * changes made directly in the entry are accepted
832 * and set in the pref. Otherwise the old value is used */
833 gtk_spin_button_update (GTK_SPIN_BUTTON (info->widget));
835 info->sane_state = TRUE;
837 set_pref_from_info_and_emit (info);
839 /* done, don't run again */
843 /* not elapsed yet, call me again */
848 spinbutton_changed_cb (GtkWidget *widget, PropertyInfo *info)
852 if ((info->apply_type & PT_AUTOAPPLY) == 0) return;
854 spin_timer = g_object_get_data (G_OBJECT (info->widget), "timer");
856 /* destroy an existing timer */
857 if (spin_timer != NULL)
859 g_timer_destroy (spin_timer);
862 /* start tnew timer */
863 spin_timer = g_timer_new();
864 g_timer_start (spin_timer);
865 g_object_set_data (G_OBJECT (info->widget), "timer", spin_timer);
867 g_timeout_add (50, (GSourceFunc) spinbutton_timeout_cb, info);
871 changed_cb (GtkWidget *widget, PropertyInfo *info)
873 info->sane_state = TRUE;
875 set_pref_from_info_and_emit (info);
879 connect_signals (gpointer key, PropertyInfo *info, EphyDialog *dialog)
883 g_return_if_fail (info->widget != NULL);
885 switch (info->widget_type)
887 case PT_TOGGLEBUTTON:
888 g_signal_connect (G_OBJECT (info->widget), "clicked",
889 G_CALLBACK (togglebutton_clicked_cb),
893 list = gtk_radio_button_get_group
894 (GTK_RADIO_BUTTON (info->widget));
895 for (; list != NULL; list = list->next)
898 (G_OBJECT (list->data), "clicked",
899 G_CALLBACK (radiobutton_clicked_cb),
904 g_signal_connect (G_OBJECT (info->widget), "changed",
905 G_CALLBACK (spinbutton_changed_cb),
909 g_signal_connect (G_OBJECT (info->widget), "changed",
910 G_CALLBACK (changed_cb), info);
913 g_signal_connect (G_OBJECT (info->widget), "changed",
914 G_CALLBACK (changed_cb), info);
922 disconnect_signals (gpointer key, PropertyInfo *info, EphyDialog *dialog)
924 g_return_if_fail (info->widget != NULL);
926 g_signal_handlers_disconnect_matched (info->widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, info);
930 init_props (EphyDialog *dialog, const EphyDialogProperty *properties, GladeXML *gxml)
934 for (i = 0 ; properties[i].id != NULL; i++)
936 PropertyInfo *info = g_new0 (PropertyInfo, 1);
938 info->id = properties[i].id;
939 info->dialog = dialog;
940 info->pref = g_strdup (properties[i].pref);
941 info->apply_type = properties[i].apply_type;
942 info->string_enum = NULL;
945 info->widget = glade_xml_get_widget (gxml, info->id);
947 if (GTK_IS_COMBO_BOX (info->widget))
949 info->widget_type = PT_COMBOBOX;
950 info->data_type = G_TYPE_INT;
952 else if (GTK_IS_SPIN_BUTTON (info->widget))
954 info->widget_type = PT_SPINBUTTON;
955 info->data_type = G_TYPE_INT;
957 else if (GTK_IS_RADIO_BUTTON (info->widget))
959 info->widget_type = PT_RADIOBUTTON;
960 info->data_type = G_TYPE_INT;
962 else if (GTK_IS_TOGGLE_BUTTON (info->widget))
964 info->widget_type = PT_TOGGLEBUTTON;
965 info->data_type = G_TYPE_BOOLEAN;
967 else if (GTK_IS_EDITABLE (info->widget))
969 info->widget_type = PT_EDITABLE;
970 info->data_type = G_TYPE_STRING;
974 info->widget_type = PT_UNKNOWN;
975 info->data_type = G_TYPE_INVALID;
978 if (properties[i].data_type != 0)
980 info->data_type = properties[i].data_type;
983 info->loaded = FALSE;
984 info->sane_state = FALSE;
986 g_hash_table_insert (dialog->priv->props, (char *) info->id, info);
991 load_info (gpointer key, PropertyInfo *info, EphyDialog *dialog)
993 GValue value = { 0, };
995 g_return_if_fail (info->widget != NULL);
997 if (info->pref != NULL)
999 set_value_from_pref (info, &value);
1000 set_info_from_value (info, &value);
1002 g_signal_emit (info->dialog, signals[CHANGED], g_quark_from_string (info->id), &value);
1004 g_value_unset (&value);
1006 set_sensitivity (info, eel_gconf_key_is_writable (info->pref));
1009 info->loaded = TRUE;
1013 save_info (gpointer key, PropertyInfo *info, EphyDialog *dialog)
1015 GValue value = { 0, };
1017 if (info->pref == NULL || (info->apply_type & PT_NORMAL) == 0)
1022 if (!info->sane_state)
1024 g_warning ("Not persisting insane state of id[%s]", info->id);
1028 if (set_value_from_info (info, &value))
1030 set_pref_from_value (info, &value);
1031 g_value_unset (&value);
1036 setup_default_size (EphyDialog *dialog)
1038 if (dialog->priv->has_default_size == FALSE)
1040 EphyStateWindowFlags flags;
1042 flags = EPHY_STATE_WINDOW_SAVE_SIZE;
1044 if (dialog->priv->persist_position)
1046 flags |= EPHY_STATE_WINDOW_SAVE_POSITION;
1049 ephy_state_add_window (dialog->priv->dialog,
1051 dialog->priv->default_width,
1052 dialog->priv->default_height,
1055 dialog->priv->has_default_size = TRUE;
1060 dialog_destroy_cb (GtkWidget *widget, EphyDialog *dialog)
1062 g_hash_table_foreach (dialog->priv->props, (GHFunc) save_info, dialog);
1064 if (dialog->priv->disposing == FALSE)
1066 g_object_unref (dialog);
1071 impl_construct (EphyDialog *dialog,
1072 const EphyDialogProperty *properties,
1077 EphyDialogPrivate *priv = dialog->priv;
1080 gxml = glade_xml_new (file, name, domain);
1081 g_return_if_fail (gxml != NULL);
1083 priv->dialog = glade_xml_get_widget (gxml, name);
1084 g_return_if_fail (priv->dialog != NULL);
1086 if (priv->name == NULL)
1088 priv->name = g_strdup (name);
1093 init_props (dialog, properties, gxml);
1096 g_signal_connect_object (dialog->priv->dialog, "destroy",
1097 G_CALLBACK(dialog_destroy_cb), dialog, 0);
1099 g_object_unref (gxml);
1103 impl_show (EphyDialog *dialog)
1105 if (dialog->priv->initialized == FALSE)
1107 dialog->priv->initialized = TRUE;
1109 g_hash_table_foreach (dialog->priv->props, (GHFunc) load_info, dialog);
1110 g_hash_table_foreach (dialog->priv->props, (GHFunc) connect_signals, dialog);
1113 setup_default_size (dialog);
1115 if (dialog->priv->parent != NULL)
1117 /* make the dialog transient again, because it seems to get
1118 * forgotten after gtk_widget_hide
1120 gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog),
1121 GTK_WINDOW (dialog->priv->parent));
1124 gtk_window_present (GTK_WINDOW (dialog->priv->dialog));
1128 ephy_dialog_set_modal (EphyDialog *dialog,
1131 dialog->priv->modal = is_modal != FALSE;
1133 gtk_window_set_modal (GTK_WINDOW(dialog->priv->dialog), is_modal);
1137 ephy_dialog_add_enum (EphyDialog *dialog,
1140 const char *const *items)
1146 info = lookup_info (dialog, id);
1147 g_return_if_fail (info != NULL);
1149 for (i = 0; i < n_items; i++)
1151 l = g_list_prepend (l, g_strdup (items[i]));
1154 info->string_enum = g_list_reverse (l);
1158 ephy_dialog_set_data_column (EphyDialog *dialog,
1164 info = lookup_info (dialog, id);
1165 g_return_if_fail (info != NULL);
1167 info->data_col = column;
1171 ephy_dialog_set_pref (EphyDialog *dialog,
1172 const char *property_id,
1177 info = lookup_info (dialog, property_id);
1178 g_return_if_fail (info != NULL);
1180 disconnect_signals (NULL, info, dialog);
1182 info->loaded = FALSE;
1183 info->sane_state = FALSE;
1184 g_free (info->pref);
1185 info->pref = g_strdup (pref);
1187 if (dialog->priv->initialized)
1189 /* dialog is already initialised, so initialise this here */
1190 load_info (NULL, info, dialog);
1191 connect_signals (NULL, info, dialog);
1196 ephy_dialog_set_size_group (EphyDialog *dialog,
1197 const char *first_id,
1200 GtkSizeGroup *size_group;
1203 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1205 va_start (vl, first_id);
1207 while (first_id != NULL)
1211 info = lookup_info (dialog, first_id);
1212 g_return_if_fail (info != NULL);
1214 g_return_if_fail (info->widget != NULL);
1216 gtk_size_group_add_widget (size_group, info->widget);
1218 first_id = va_arg (vl, const char*);
1223 g_object_unref (size_group);
1227 ephy_dialog_construct (EphyDialog *dialog,
1228 const EphyDialogProperty *properties,
1233 EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
1234 klass->construct (dialog, properties, file, name, domain);
1238 ephy_dialog_show (EphyDialog *dialog)
1240 EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
1241 klass->show (dialog);
1245 ephy_dialog_hide (EphyDialog *dialog)
1247 g_return_if_fail (EPHY_IS_DIALOG (dialog));
1248 g_return_if_fail (dialog->priv->dialog != NULL);
1250 gtk_widget_hide (dialog->priv->dialog);
1254 ephy_dialog_run (EphyDialog *dialog)
1256 ephy_dialog_show (dialog);
1258 gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (dialog->priv->parent)),
1259 GTK_WINDOW (dialog->priv->dialog));
1261 return gtk_dialog_run (GTK_DIALOG (dialog->priv->dialog));
1265 ephy_dialog_get_control (EphyDialog *dialog,
1266 const char *property_id)
1270 info = lookup_info (dialog, property_id);
1271 g_return_val_if_fail (info != NULL, NULL);
1273 return info->widget;
1277 ephy_dialog_get_controls (EphyDialog *dialog,
1278 const char *property_id,
1285 va_start (varargs, property_id);
1287 while (property_id != NULL)
1289 info = lookup_info (dialog, property_id);
1290 g_return_if_fail (info != NULL);
1292 wptr = va_arg (varargs, GtkWidget **);
1293 *wptr = info->widget;
1295 property_id = va_arg (varargs, const char *);
1302 ephy_dialog_get_value (EphyDialog *dialog,
1303 const char *property_id,
1308 info = lookup_info (dialog, property_id);
1309 g_return_val_if_fail (info != NULL, FALSE);
1311 return set_value_from_info (info, value);
1315 ephy_dialog_set_value (EphyDialog *dialog,
1316 const char *property_id,
1317 const GValue *value)
1321 info = lookup_info (dialog, property_id);
1322 g_return_if_fail (info != NULL);
1324 set_info_from_value (info, value);
1328 free_prop_info (PropertyInfo *info)
1330 if (info->string_enum)
1332 g_list_foreach (info->string_enum, (GFunc)g_free, NULL);
1333 g_list_free (info->string_enum);
1336 g_free (info->pref);
1342 ephy_dialog_init (EphyDialog *dialog)
1344 dialog->priv = EPHY_DIALOG_GET_PRIVATE (dialog);
1346 dialog->priv->default_width = -1;
1347 dialog->priv->default_height = -1;
1349 dialog->priv->props = g_hash_table_new_full
1350 (g_str_hash, g_str_equal, NULL, (GDestroyNotify) free_prop_info);
1354 ephy_dialog_dispose (GObject *object)
1356 EphyDialog *dialog = EPHY_DIALOG (object);
1358 if (dialog->priv->dialog)
1360 dialog->priv->disposing = TRUE;
1361 gtk_widget_destroy (dialog->priv->dialog);
1362 dialog->priv->dialog = NULL;
1365 parent_class->dispose (object);
1369 ephy_dialog_finalize (GObject *object)
1371 EphyDialog *dialog = EPHY_DIALOG (object);
1373 g_hash_table_destroy (dialog->priv->props);
1375 g_free (dialog->priv->name);
1377 G_OBJECT_CLASS (parent_class)->finalize (object);
1381 ephy_dialog_get_parent (EphyDialog *dialog)
1383 g_return_val_if_fail (EPHY_IS_DIALOG (dialog), NULL);
1385 return dialog->priv->parent;
1389 ephy_dialog_set_parent (EphyDialog *dialog,
1392 dialog->priv->parent = parent;
1394 g_object_notify (G_OBJECT (dialog), "parent-window");
1398 ephy_dialog_set_property (GObject *object,
1400 const GValue *value,
1403 EphyDialog *dialog = EPHY_DIALOG (object);
1407 case PROP_PARENT_WINDOW:
1408 ephy_dialog_set_parent (dialog, g_value_get_object (value));
1411 ephy_dialog_set_modal (dialog, g_value_get_boolean (value));
1413 case PROP_PERSIST_POSITION:
1414 dialog->priv->persist_position = g_value_get_boolean (value);
1416 case PROP_DEFAULT_WIDTH:
1417 dialog->priv->default_width = g_value_get_int (value);
1419 case PROP_DEFAULT_HEIGHT:
1420 dialog->priv->default_height = g_value_get_int (value);
1426 ephy_dialog_get_property (GObject *object,
1431 EphyDialog *dialog = EPHY_DIALOG (object);
1435 case PROP_PARENT_WINDOW:
1436 g_value_set_object (value, dialog->priv->parent);
1439 g_value_set_boolean (value, dialog->priv->modal);
1441 case PROP_PERSIST_POSITION:
1442 g_value_set_boolean (value, dialog->priv->persist_position);
1444 case PROP_DEFAULT_WIDTH:
1445 g_value_set_int (value, dialog->priv->default_width);
1447 case PROP_DEFAULT_HEIGHT:
1448 g_value_set_int (value, dialog->priv->default_height);
1454 ephy_dialog_class_init (EphyDialogClass *klass)
1456 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1458 parent_class = g_type_class_peek_parent (klass);
1460 object_class->finalize = ephy_dialog_finalize;
1461 object_class->dispose = ephy_dialog_dispose;
1462 object_class->set_property = ephy_dialog_set_property;
1463 object_class->get_property = ephy_dialog_get_property;
1465 klass->construct = impl_construct;
1466 klass->show = impl_show;
1469 g_signal_new ("changed",
1471 G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
1472 G_STRUCT_OFFSET (EphyDialogClass, changed),
1474 g_cclosure_marshal_VOID__POINTER,
1479 g_object_class_install_property (object_class,
1481 g_param_spec_object ("parent-window",
1485 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
1487 g_object_class_install_property (object_class,
1489 g_param_spec_boolean ("Modal",
1493 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
1495 g_object_class_install_property (object_class,
1496 PROP_PERSIST_POSITION,
1497 g_param_spec_boolean ("persist-position",
1499 "Persist dialog position",
1501 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
1502 G_PARAM_CONSTRUCT_ONLY));
1504 g_object_class_install_property (object_class,
1506 g_param_spec_int ("default-width",
1508 "Default dialog width",
1512 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
1513 G_PARAM_CONSTRUCT_ONLY));
1515 g_object_class_install_property (object_class,
1516 PROP_DEFAULT_HEIGHT,
1517 g_param_spec_int ("default-height",
1519 "Default dialog height",
1523 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
1524 G_PARAM_CONSTRUCT_ONLY));
1526 g_type_class_add_private (object_class, sizeof (EphyDialogPrivate));
1530 ephy_dialog_new (void)
1532 return EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG, NULL));
1536 ephy_dialog_new_with_parent (GtkWidget *parent_window)
1538 return EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG,
1539 "parent-window", parent_window,