diff options
Diffstat (limited to 'capplets/common/mateconf-property-editor.c')
-rw-r--r-- | capplets/common/mateconf-property-editor.c | 1801 |
1 files changed, 1801 insertions, 0 deletions
diff --git a/capplets/common/mateconf-property-editor.c b/capplets/common/mateconf-property-editor.c new file mode 100644 index 00000000..f565a168 --- /dev/null +++ b/capplets/common/mateconf-property-editor.c @@ -0,0 +1,1801 @@ +/* -*- mode: c; style: linux -*- */ + +/* mateconf-property-editor.c + * Copyright (C) 2001 Ximian, Inc. + * + * Written by Bradford Hovinen <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> + +#include "mateconf-property-editor.h" +#include "mateconf-property-editor-marshal.h" + +enum { + VALUE_CHANGED, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_KEY, + PROP_CALLBACK, + PROP_CHANGESET, + PROP_CONV_TO_WIDGET_CB, + PROP_CONV_FROM_WIDGET_CB, + PROP_UI_CONTROL, + PROP_DATA, + PROP_DATA_FREE_CB +}; + +struct _MateConfPropertyEditorPrivate +{ + gchar *key; + guint handler_id; + MateConfChangeSet *changeset; + GObject *ui_control; + MateConfPEditorValueConvFn conv_to_widget_cb; + MateConfPEditorValueConvFn conv_from_widget_cb; + MateConfClientNotifyFunc callback; + gboolean inited; + + gpointer data; + GFreeFunc data_free_cb; +}; + +typedef struct +{ + GType enum_type; + MateConfPEditorGetValueFn enum_val_true_fn; + gpointer enum_val_true_fn_data; + guint enum_val_false; + gboolean use_nick; +} MateConfPropertyEditorEnumData; + +static guint peditor_signals[LAST_SIGNAL]; + +static void mateconf_property_editor_set_prop (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void mateconf_property_editor_get_prop (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void mateconf_property_editor_finalize (GObject *object); + +static GObject *mateconf_peditor_new (const gchar *key, + MateConfClientNotifyFunc cb, + MateConfChangeSet *changeset, + GObject *ui_control, + const gchar *first_prop_name, + va_list var_args, + const gchar *first_custom, + ...); + +G_DEFINE_TYPE (MateConfPropertyEditor, mateconf_property_editor, G_TYPE_OBJECT) + +#define MATECONF_PROPERTY_EDITOR_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), mateconf_property_editor_get_type (), MateConfPropertyEditorPrivate)) + + +static MateConfValue* +mateconf_property_editor_conv_default (MateConfPropertyEditor *peditor, + const MateConfValue *value) +{ + return mateconf_value_copy (value); +} + +static void +mateconf_property_editor_init (MateConfPropertyEditor *mateconf_property_editor) +{ + mateconf_property_editor->p = MATECONF_PROPERTY_EDITOR_GET_PRIVATE (mateconf_property_editor); + mateconf_property_editor->p->conv_to_widget_cb = mateconf_property_editor_conv_default; + mateconf_property_editor->p->conv_from_widget_cb = mateconf_property_editor_conv_default; + mateconf_property_editor->p->inited = FALSE; +} + +static void +mateconf_property_editor_class_init (MateConfPropertyEditorClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = mateconf_property_editor_finalize; + object_class->set_property = mateconf_property_editor_set_prop; + object_class->get_property = mateconf_property_editor_get_prop; + + g_object_class_install_property + (object_class, PROP_KEY, + g_param_spec_string ("key", + _("Key"), + _("MateConf key to which this property editor is attached"), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property + (object_class, PROP_CALLBACK, + g_param_spec_pointer ("callback", + _("Callback"), + _("Issue this callback when the value associated with key gets changed"), + G_PARAM_WRITABLE)); + g_object_class_install_property + (object_class, PROP_CHANGESET, + g_param_spec_pointer ("changeset", + _("Change set"), + _("MateConf change set containing data to be forwarded to the mateconf client on apply"), + G_PARAM_READWRITE)); + g_object_class_install_property + (object_class, PROP_CONV_TO_WIDGET_CB, + g_param_spec_pointer ("conv-to-widget-cb", + _("Conversion to widget callback"), + _("Callback to be issued when data are to be converted from MateConf to the widget"), + G_PARAM_WRITABLE)); + g_object_class_install_property + (object_class, PROP_CONV_FROM_WIDGET_CB, + g_param_spec_pointer ("conv-from-widget-cb", + _("Conversion from widget callback"), + _("Callback to be issued when data are to be converted to MateConf from the widget"), + G_PARAM_WRITABLE)); + g_object_class_install_property + (object_class, PROP_UI_CONTROL, + g_param_spec_object ("ui-control", + _("UI Control"), + _("Object that controls the property (normally a widget)"), + G_TYPE_OBJECT, + G_PARAM_WRITABLE)); + + peditor_signals[VALUE_CHANGED] = + g_signal_new ("value-changed", + G_TYPE_FROM_CLASS (object_class), 0, + G_STRUCT_OFFSET (MateConfPropertyEditorClass, value_changed), + NULL, NULL, + (GSignalCMarshaller) mateconf_property_editor_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER); + + g_object_class_install_property + (object_class, PROP_DATA, + g_param_spec_pointer ("data", + _("Property editor object data"), + _("Custom data required by the specific property editor"), + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, PROP_DATA_FREE_CB, + g_param_spec_pointer ("data-free-cb", + _("Property editor data freeing callback"), + _("Callback to be issued when property editor object data is to be freed"), + G_PARAM_WRITABLE)); + + g_type_class_add_private (class, sizeof (MateConfPropertyEditorPrivate)); +} + +static void +mateconf_property_editor_set_prop (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MateConfPropertyEditor *peditor; + MateConfClient *client; + MateConfNotifyFunc cb; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (object)); + + peditor = MATECONF_PROPERTY_EDITOR (object); + + switch (prop_id) { + case PROP_KEY: + peditor->p->key = g_value_dup_string (value); + break; + + case PROP_CALLBACK: + client = mateconf_client_get_default (); + cb = g_value_get_pointer (value); + peditor->p->callback = (MateConfClientNotifyFunc) cb; + if (peditor->p->handler_id != 0) { + mateconf_client_notify_remove (client, + peditor->p->handler_id); + } + peditor->p->handler_id = + mateconf_client_notify_add (client, peditor->p->key, + peditor->p->callback, + peditor, NULL, NULL); + g_object_unref (client); + break; + + case PROP_CHANGESET: + peditor->p->changeset = g_value_get_pointer (value); + break; + + case PROP_CONV_TO_WIDGET_CB: + peditor->p->conv_to_widget_cb = g_value_get_pointer (value); + break; + + case PROP_CONV_FROM_WIDGET_CB: + peditor->p->conv_from_widget_cb = g_value_get_pointer (value); + break; + + case PROP_UI_CONTROL: + peditor->p->ui_control = g_value_get_object (value); + g_object_weak_ref (peditor->p->ui_control, (GWeakNotify) g_object_unref, object); + break; + case PROP_DATA: + peditor->p->data = g_value_get_pointer (value); + break; + case PROP_DATA_FREE_CB: + peditor->p->data_free_cb = g_value_get_pointer (value); + break; + default: + g_warning ("Bad argument set"); + break; + } +} + +static void +mateconf_property_editor_get_prop (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MateConfPropertyEditor *peditor; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (object)); + + peditor = MATECONF_PROPERTY_EDITOR (object); + + switch (prop_id) { + case PROP_KEY: + g_value_set_string (value, peditor->p->key); + break; + + case PROP_CHANGESET: + g_value_set_pointer (value, peditor->p->changeset); + break; + + case PROP_DATA: + g_value_set_pointer (value, peditor->p->data); + break; + default: + g_warning ("Bad argument get"); + break; + } +} + +static void +mateconf_property_editor_finalize (GObject *object) +{ + MateConfPropertyEditor *mateconf_property_editor; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (object)); + + mateconf_property_editor = MATECONF_PROPERTY_EDITOR (object); + + g_free (mateconf_property_editor->p->key); + + if (mateconf_property_editor->p->data_free_cb) + mateconf_property_editor->p->data_free_cb (mateconf_property_editor->p->data); + + if (mateconf_property_editor->p->handler_id != 0) { + MateConfClient *client; + + client = mateconf_client_get_default (); + mateconf_client_notify_remove (client, + mateconf_property_editor->p->handler_id); + g_object_unref (client); + } + + G_OBJECT_CLASS (mateconf_property_editor_parent_class)->finalize (object); +} + +static GObject * +mateconf_peditor_new (const gchar *key, + MateConfClientNotifyFunc cb, + MateConfChangeSet *changeset, + GObject *ui_control, + const gchar *first_prop_name, + va_list var_args, + const gchar *first_custom, + ...) +{ + GObject *obj; + MateConfClient *client; + MateConfEntry *mateconf_entry; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (cb != NULL, NULL); + + obj = g_object_new (mateconf_property_editor_get_type (), + "key", key, + "callback", cb, + "changeset", changeset, + "ui-control", ui_control, + NULL); + + g_object_set_valist (obj, first_prop_name, var_args); + + if (first_custom) + { + va_list custom_args; + va_start (custom_args, first_custom); + g_object_set_valist (obj, first_custom, custom_args); + va_end (custom_args); + } + + client = mateconf_client_get_default (); + mateconf_entry = mateconf_client_get_entry (client, MATECONF_PROPERTY_EDITOR (obj)->p->key, NULL, TRUE, NULL); + MATECONF_PROPERTY_EDITOR (obj)->p->callback (client, 0, mateconf_entry, obj); + MATECONF_PROPERTY_EDITOR (obj)->p->inited = TRUE; + if (mateconf_entry) + mateconf_entry_free (mateconf_entry); + g_object_unref (client); + + return obj; +} + +const gchar * +mateconf_property_editor_get_key (MateConfPropertyEditor *peditor) +{ + return peditor->p->key; +} + +GObject * +mateconf_property_editor_get_ui_control (MateConfPropertyEditor *peditor) +{ + return peditor->p->ui_control; +} + +static void +peditor_set_mateconf_value (MateConfPropertyEditor *peditor, + const gchar *key, + MateConfValue *value) +{ + + if (peditor->p->changeset != NULL) { + if (value) + mateconf_change_set_set (peditor->p->changeset, peditor->p->key, value); + else + mateconf_change_set_unset (peditor->p->changeset, peditor->p->key); + } else { + MateConfClient *client = mateconf_client_get_default(); + + if (value) + mateconf_client_set (client, peditor->p->key, value, NULL); + else + mateconf_client_unset (client, peditor->p->key, NULL); + + g_object_unref (client); + } + +} + +static void +peditor_boolean_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (peditor->p->ui_control), mateconf_value_get_bool (value_wid)); + mateconf_value_free (value_wid); + } +} + +static void +peditor_boolean_widget_changed (MateConfPropertyEditor *peditor, + GtkToggleButton *tb) +{ + MateConfValue *value, *value_wid; + + if (!peditor->p->inited) return; + value_wid = mateconf_value_new (MATECONF_VALUE_BOOL); + mateconf_value_set_bool (value_wid, gtk_toggle_button_get_active (tb)); + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + mateconf_value_free (value_wid); + mateconf_value_free (value); +} + +GObject * +mateconf_peditor_new_boolean (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *checkbox, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (checkbox != NULL, NULL); + g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (checkbox), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_boolean_value_changed, + changeset, + G_OBJECT (checkbox), + first_property_name, + var_args, + NULL); + + va_end (var_args); + + g_signal_connect_swapped (checkbox, "toggled", + (GCallback) peditor_boolean_widget_changed, peditor); + + return peditor; +} + +static void +peditor_integer_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + const char *entry_current_text; + int entry_current_integer; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + entry_current_text = gtk_entry_get_text (GTK_ENTRY (peditor->p->ui_control)); + entry_current_integer = strtol (entry_current_text, NULL, 10); + if (entry_current_integer != mateconf_value_get_int (value)) { + char *buf = g_strdup_printf ("%d", mateconf_value_get_int (value_wid)); + gtk_entry_set_text (GTK_ENTRY (peditor->p->ui_control), buf); + g_free (buf); + } + mateconf_value_free (value_wid); + } +} + +static void +peditor_integer_widget_changed (MateConfPropertyEditor *peditor, + GtkEntry *entry) +{ + MateConfValue *value, *value_wid; + + if (!peditor->p->inited) return; + + value_wid = mateconf_value_new (MATECONF_VALUE_INT); + + mateconf_value_set_int (value_wid, strtol (gtk_entry_get_text (entry), NULL, 10)); + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + + peditor_set_mateconf_value (peditor, peditor->p->key, value); + + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + mateconf_value_free (value_wid); + mateconf_value_free (value); +} + +static GObject * +mateconf_peditor_new_integer_valist (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *entry, + const gchar *first_property_name, + va_list var_args) +{ + GObject *peditor; + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_integer_value_changed, + changeset, + G_OBJECT (entry), + first_property_name, + var_args, NULL); + + g_signal_connect_swapped (entry, "changed", + (GCallback) peditor_integer_widget_changed, peditor); + + return peditor; +} + +GObject * +mateconf_peditor_new_integer (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *entry, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new_integer_valist + (changeset, key, entry, + first_property_name, var_args); + + va_end (var_args); + + return peditor; +} + +static void +peditor_string_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + const char *entry_current_text; + const char *mateconf_text; + + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + mateconf_text = mateconf_value_get_string (value_wid); + entry_current_text = gtk_entry_get_text (GTK_ENTRY (peditor->p->ui_control)); + + if (mateconf_text && strcmp (entry_current_text, mateconf_text) != 0) { + gtk_entry_set_text (GTK_ENTRY (peditor->p->ui_control), mateconf_value_get_string (value_wid)); + } + mateconf_value_free (value_wid); + } +} + +static void +peditor_string_widget_changed (MateConfPropertyEditor *peditor, + GtkEntry *entry) +{ + MateConfValue *value, *value_wid; + + if (!peditor->p->inited) return; + + value_wid = mateconf_value_new (MATECONF_VALUE_STRING); + + mateconf_value_set_string (value_wid, gtk_entry_get_text (entry)); + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + + peditor_set_mateconf_value (peditor, peditor->p->key, value); + + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + mateconf_value_free (value_wid); + mateconf_value_free (value); +} + +static GObject * +mateconf_peditor_new_string_valist (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *entry, + const gchar *first_property_name, + va_list var_args) +{ + GObject *peditor; + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_string_value_changed, + changeset, + G_OBJECT (entry), + first_property_name, + var_args, NULL); + + g_signal_connect_swapped (entry, "changed", + (GCallback) peditor_string_widget_changed, peditor); + + return peditor; +} + +GObject * +mateconf_peditor_new_string (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *entry, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new_string_valist + (changeset, key, entry, + first_property_name, var_args); + + va_end (var_args); + + return peditor; +} + +static void +peditor_color_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + const gchar *spec; + + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + spec = mateconf_value_get_string (value_wid); + if (spec) { + GdkColor color; + gdk_color_parse (mateconf_value_get_string (value_wid), &color); + gtk_color_button_set_color ( + GTK_COLOR_BUTTON (peditor->p->ui_control), &color); + } + mateconf_value_free (value_wid); + } +} + +static void +peditor_color_widget_changed (MateConfPropertyEditor *peditor, + GtkColorButton *cb) +{ + gchar *str; + MateConfValue *value, *value_wid; + GdkColor color; + + if (!peditor->p->inited) return; + + value_wid = mateconf_value_new (MATECONF_VALUE_STRING); + gtk_color_button_get_color (cb, &color); + str = g_strdup_printf ("#%02x%02x%02x", color.red >> 8, + color.green >> 8, color.blue >> 8); + mateconf_value_set_string (value_wid, str); + g_free (str); + + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + + mateconf_value_free (value_wid); + mateconf_value_free (value); +} + +GObject * +mateconf_peditor_new_color (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *cb, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (cb != NULL, NULL); + g_return_val_if_fail (GTK_IS_COLOR_BUTTON (cb), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_color_value_changed, + changeset, + G_OBJECT (cb), + first_property_name, + var_args, NULL); + + va_end (var_args); + + g_signal_connect_swapped (cb, "color_set", + (GCallback) peditor_color_widget_changed, peditor); + + return peditor; +} + +static int +peditor_enum_int_from_string (GType type, const gchar *str, gboolean use_nick) +{ + GEnumClass *klass; + GEnumValue *val; + int ret = -1; + + klass = g_type_class_ref (type); + if (use_nick) + val = g_enum_get_value_by_nick (klass, str); + else + val = g_enum_get_value_by_name (klass, str); + + g_type_class_unref (klass); + + if (val) + ret = val->value; + + return ret; +} + +static gchar* +peditor_enum_string_from_int (GType type, const int index, gboolean use_nick) +{ + GEnumClass *klass; + GEnumValue *val; + gchar *ret = NULL; + + klass = g_type_class_ref (type); + val = g_enum_get_value (klass, index); + if (val) + { + if (val->value_nick && use_nick) + ret = g_strdup (val->value_nick); + else + ret = g_strdup (val->value_name); + } + + g_type_class_unref (klass); + + return ret; +} + +static MateConfValue* +peditor_enum_conv_to_widget (MateConfPropertyEditor *peditor, + const MateConfValue *value) +{ + MateConfValue *ret; + MateConfPropertyEditorEnumData *data = peditor->p->data; + int index; + + if (value->type == MATECONF_VALUE_INT) + return mateconf_value_copy (value); + + ret = mateconf_value_new (MATECONF_VALUE_INT); + + index = peditor_enum_int_from_string (data->enum_type, + mateconf_value_get_string (value), + data->use_nick); + + mateconf_value_set_int (ret, index); + + return ret; +} + +static MateConfValue* +peditor_enum_conv_from_widget (MateConfPropertyEditor *peditor, + const MateConfValue *value) +{ + MateConfValue *ret; + MateConfPropertyEditorEnumData *data = peditor->p->data; + gchar *str; + + if (value->type == MATECONF_VALUE_STRING) + return mateconf_value_copy (value); + + ret = mateconf_value_new (MATECONF_VALUE_STRING); + str = peditor_enum_string_from_int (data->enum_type, + mateconf_value_get_int (value), + data->use_nick); + mateconf_value_set_string (ret, str); + g_free (str); + + return ret; +} + +static void +peditor_combo_box_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + gtk_combo_box_set_active (GTK_COMBO_BOX (peditor->p->ui_control), mateconf_value_get_int (value_wid)); + mateconf_value_free (value_wid); + } +} + +static void +peditor_combo_box_widget_changed (MateConfPropertyEditor *peditor, + GtkComboBox *combo_box) +{ + MateConfValue *value, *value_wid; + + if (!peditor->p->inited) return; + value_wid = mateconf_value_new (MATECONF_VALUE_INT); + mateconf_value_set_int (value_wid, gtk_combo_box_get_active (combo_box)); + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + mateconf_value_free (value_wid); + if (value) + mateconf_value_free (value); +} + +GObject * +mateconf_peditor_new_combo_box (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *combo_box, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (combo_box != NULL, NULL); + g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_combo_box_value_changed, + changeset, + G_OBJECT (combo_box), + first_property_name, + var_args, NULL); + + va_end (var_args); + + g_signal_connect_swapped (combo_box, "changed", + (GCallback) peditor_combo_box_widget_changed, peditor); + + return peditor; +} + +GObject * +mateconf_peditor_new_combo_box_with_enum (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *combo_box, + GType enum_type, + gboolean use_nick, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + MateConfPropertyEditorEnumData *data; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (combo_box != NULL, NULL); + g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL); + g_return_val_if_fail (enum_type != G_TYPE_NONE, NULL); + + data = g_new0 (MateConfPropertyEditorEnumData, 1); + data->enum_type = enum_type; + data->use_nick = use_nick; + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_combo_box_value_changed, + changeset, + G_OBJECT (combo_box), + first_property_name, + var_args, + "conv-to-widget-cb", + peditor_enum_conv_to_widget, + "conv-from-widget-cb", + peditor_enum_conv_from_widget, + "data", + data, + "data-free-cb", + g_free, + NULL + ); + + va_end (var_args); + + g_signal_connect_swapped (combo_box, "changed", + (GCallback) peditor_combo_box_widget_changed, peditor); + + return peditor; +} + +static void +peditor_select_radio_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + GSList *group, *link; + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + group = g_slist_copy (gtk_radio_button_get_group (GTK_RADIO_BUTTON (peditor->p->ui_control))); + group = g_slist_reverse (group); + link = g_slist_nth (group, mateconf_value_get_int (value_wid)); + if (link && link->data) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (link->data), TRUE); + mateconf_value_free (value_wid); + g_slist_free (group); + } +} + +static void +peditor_select_radio_widget_changed (MateConfPropertyEditor *peditor, + GtkToggleButton *tb) +{ + GSList *group; + MateConfValue *value, *value_wid; + + if (!peditor->p->inited) return; + if (!gtk_toggle_button_get_active (tb)) return; + + value_wid = mateconf_value_new (MATECONF_VALUE_INT); + group = g_slist_copy (gtk_radio_button_get_group (GTK_RADIO_BUTTON (peditor->p->ui_control))); + group = g_slist_reverse (group); + + mateconf_value_set_int (value_wid, g_slist_index (group, tb)); + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + + mateconf_value_free (value_wid); + mateconf_value_free (value); + g_slist_free (group); +} + +GObject * +mateconf_peditor_new_select_radio (MateConfChangeSet *changeset, + const gchar *key, + GSList *radio_group, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + GtkRadioButton *first_button; + GSList *item; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (radio_group != NULL, NULL); + g_return_val_if_fail (radio_group->data != NULL, NULL); + g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_group->data), NULL); + + first_button = GTK_RADIO_BUTTON (radio_group->data); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_select_radio_value_changed, + changeset, + G_OBJECT (first_button), + first_property_name, + var_args, NULL); + + va_end (var_args); + + for (item = radio_group; item != NULL; item = item->next) + g_signal_connect_swapped (item->data, "toggled", + (GCallback) peditor_select_radio_widget_changed, peditor); + + return peditor; +} + +static void +peditor_numeric_range_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + + switch (value_wid->type) { + case MATECONF_VALUE_FLOAT: + gtk_adjustment_set_value (GTK_ADJUSTMENT (peditor->p->ui_control), mateconf_value_get_float (value_wid)); + break; + case MATECONF_VALUE_INT: + gtk_adjustment_set_value (GTK_ADJUSTMENT (peditor->p->ui_control), mateconf_value_get_int (value_wid)); + break; + default: + g_warning ("Unknown type in range peditor: %d\n", value_wid->type); + } + mateconf_value_free (value_wid); + } +} + +static void +peditor_numeric_range_widget_changed (MateConfPropertyEditor *peditor, + GtkAdjustment *adjustment) +{ + MateConfValue *value, *value_wid, *default_value; + MateConfClient *client; + + if (!peditor->p->inited) return; + + /* We try to get the default type from the schemas. if not, we default + * to an int. + */ + client = mateconf_client_get_default(); + + default_value = mateconf_client_get_default_from_schema (client, + peditor->p->key, + NULL); + g_object_unref (client); + + if (default_value) { + value_wid = mateconf_value_new (default_value->type); + mateconf_value_free (default_value); + } else { + g_warning ("Unable to find a default value for key for %s.\n" + "I'll assume it is an integer, but that may break things.\n" + "Please be sure that the associated schema is installed", + peditor->p->key); + value_wid = mateconf_value_new (MATECONF_VALUE_INT); + } + + g_assert (value_wid); + + if (value_wid->type == MATECONF_VALUE_INT) + mateconf_value_set_int (value_wid, gtk_adjustment_get_value (adjustment)); + else if (value_wid->type == MATECONF_VALUE_FLOAT) + mateconf_value_set_float (value_wid, gtk_adjustment_get_value (adjustment)); + else { + g_warning ("unable to set a mateconf key for %s of type %d", + peditor->p->key, + value_wid->type); + mateconf_value_free (value_wid); + return; + } + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + mateconf_value_free (value_wid); + mateconf_value_free (value); +} + +GObject * +mateconf_peditor_new_numeric_range (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *range, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + GObject *adjustment = NULL; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (range != NULL, NULL); + g_return_val_if_fail (GTK_IS_RANGE (range)||GTK_IS_SPIN_BUTTON (range), NULL); + + if (GTK_IS_RANGE (range)) + adjustment = G_OBJECT (gtk_range_get_adjustment (GTK_RANGE (range))); + else if (GTK_IS_SPIN_BUTTON (range)) + adjustment = G_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (range))); + else + g_assert_not_reached (); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_numeric_range_value_changed, + changeset, + adjustment, + first_property_name, + var_args, NULL); + + va_end (var_args); + + g_signal_connect_swapped (adjustment, "value_changed", + (GCallback) peditor_numeric_range_widget_changed, peditor); + + return peditor; +} + +static gboolean +guard_get_bool (MateConfPropertyEditor *peditor, const MateConfValue *value) +{ + if (value->type == MATECONF_VALUE_BOOL) + return mateconf_value_get_bool (value); + else + { + MateConfPropertyEditorEnumData *data = peditor->p->data; + int index = peditor_enum_int_from_string (data->enum_type, mateconf_value_get_string (value), data->use_nick); + return (index != data->enum_val_false); + } +} + +static void +guard_value_changed (MateConfPropertyEditor *peditor, + const gchar *key, + const MateConfValue *value, + GtkWidget *widget) +{ + gtk_widget_set_sensitive (widget, guard_get_bool (peditor, value)); +} + +void +mateconf_peditor_widget_set_guard (MateConfPropertyEditor *peditor, + GtkWidget *widget) +{ + MateConfClient *client; + MateConfValue *value; + + g_return_if_fail (peditor != NULL); + g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (peditor)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + client = mateconf_client_get_default (); + value = mateconf_client_get (client, peditor->p->key, NULL); + g_object_unref (client); + + if (value) { + gtk_widget_set_sensitive (widget, guard_get_bool (peditor, value)); + mateconf_value_free (value); + } else { + g_warning ("NULL MateConf value: %s: possibly incomplete setup", peditor->p->key); + } + + g_signal_connect (peditor, "value-changed", (GCallback) guard_value_changed, widget); +} + +MateConfValue * +mateconf_value_int_to_float (MateConfPropertyEditor *ignored, const MateConfValue *value) +{ + MateConfValue *new_value; + + new_value = mateconf_value_new (MATECONF_VALUE_FLOAT); + mateconf_value_set_float (new_value, mateconf_value_get_int (value)); + return new_value; +} + +MateConfValue * +mateconf_value_float_to_int (MateConfPropertyEditor *ignored, const MateConfValue *value) +{ + MateConfValue *new_value; + + new_value = mateconf_value_new (MATECONF_VALUE_INT); + mateconf_value_set_int (new_value, mateconf_value_get_float (value)); + return new_value; +} + +static void +peditor_font_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + const gchar *font; + + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + font = mateconf_value_get_string (value_wid); + gtk_font_button_set_font_name (GTK_FONT_BUTTON (peditor->p->ui_control), + font); + mateconf_value_free (value_wid); + } +} + +static void +peditor_font_widget_changed (MateConfPropertyEditor *peditor, + GtkFontButton *font_button) +{ + const gchar *font_name; + MateConfValue *value, *value_wid = NULL; + + if (!peditor->p->inited) + return; + + font_name = gtk_font_button_get_font_name (font_button); + + value_wid = mateconf_value_new (MATECONF_VALUE_STRING); + mateconf_value_set_string (value_wid, font_name); + + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + + mateconf_value_free (value_wid); + mateconf_value_free (value); +} + +GObject * +mateconf_peditor_new_font (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *font_button, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (GTK_IS_FONT_BUTTON (font_button), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new (key, + (MateConfClientNotifyFunc) peditor_font_value_changed, + changeset, + G_OBJECT (font_button), + first_property_name, + var_args, + NULL); + + va_end (var_args); + + g_signal_connect_swapped (font_button, "font_set", + (GCallback) peditor_font_widget_changed, peditor); + + return peditor; +} + +static MateConfValue* +peditor_enum_toggle_conv_to_widget (MateConfPropertyEditor *peditor, + const MateConfValue *value) +{ + MateConfValue *ret; + MateConfPropertyEditorEnumData *data = peditor->p->data; + int index; + + if (value->type == MATECONF_VALUE_BOOL) + return mateconf_value_copy (value); + + ret = mateconf_value_new (MATECONF_VALUE_BOOL); + + index = peditor_enum_int_from_string (data->enum_type, + mateconf_value_get_string (value), + data->use_nick); + mateconf_value_set_bool (ret, (index != data->enum_val_false)); + + return ret; +} + +static MateConfValue* +peditor_enum_toggle_conv_from_widget (MateConfPropertyEditor *peditor, + const MateConfValue *value) +{ + MateConfValue *ret; + MateConfPropertyEditorEnumData *data = peditor->p->data; + gchar *str; + int index; + + if (value->type == MATECONF_VALUE_STRING) + return mateconf_value_copy (value); + + ret = mateconf_value_new (MATECONF_VALUE_STRING); + if (mateconf_value_get_bool (value)) + index = data->enum_val_true_fn (peditor, data->enum_val_true_fn_data); + else + index = data->enum_val_false; + + str = peditor_enum_string_from_int (data->enum_type, index, data->use_nick); + mateconf_value_set_string (ret, str); + g_free (str); + + return ret; +} + +GObject * +mateconf_peditor_new_enum_toggle (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *checkbox, + GType enum_type, + MateConfPEditorGetValueFn val_true_fn, + guint val_false, + gboolean use_nick, + gpointer data, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + MateConfPropertyEditorEnumData *enum_data; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (checkbox != NULL, NULL); + g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (checkbox), NULL); + + enum_data = g_new0 (MateConfPropertyEditorEnumData, 1); + enum_data->enum_type = enum_type; + enum_data->enum_val_true_fn = val_true_fn; + enum_data->enum_val_true_fn_data = data; + enum_data->enum_val_false = val_false; + enum_data->use_nick = use_nick; + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_boolean_value_changed, + changeset, + G_OBJECT (checkbox), + first_property_name, + var_args, + "conv-to-widget-cb", + peditor_enum_toggle_conv_to_widget, + "conv-from-widget-cb", + peditor_enum_toggle_conv_from_widget, + "data", + enum_data, + "data-free-cb", + g_free, + NULL); + + va_end (var_args); + + g_signal_connect_swapped (checkbox, "toggled", + (GCallback) peditor_boolean_widget_changed, peditor); + + return peditor; +} + +static gboolean +peditor_image_set_filename (MateConfPropertyEditor *peditor, const gchar *filename) +{ + GdkPixbuf *pixbuf = NULL; + GtkImage *image = NULL; + const int scale = 100; + gchar *message = NULL; + GtkWidget *ui_control_child; + GList *l; + + /* NULL is not valid, however "" is, but not an error (it's + * the default) */ + g_return_val_if_fail (filename != NULL, FALSE); + + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + { + message = g_strdup_printf (_("Couldn't find the file '%s'.\n\nPlease make " + "sure it exists and try again, " + "or choose a different background picture."), + filename); + + } + else if (!(pixbuf = gdk_pixbuf_new_from_file_at_size (filename, scale, scale, NULL))) + { + message = g_strdup_printf (_("I don't know how to open the file '%s'.\n" + "Perhaps it's " + "a kind of picture that is not yet supported.\n\n" + "Please select a different picture instead."), + filename); + } + + ui_control_child = gtk_bin_get_child (GTK_BIN (peditor->p->ui_control)); + + if (GTK_IS_IMAGE (ui_control_child)) + image = GTK_IMAGE (ui_control_child); + else + { + for (l = gtk_container_get_children (GTK_CONTAINER (ui_control_child)); l != NULL; l = l->next) + { + if (GTK_IS_IMAGE (l->data)) + image = GTK_IMAGE (l->data); + else if (GTK_IS_LABEL (l->data) && message == NULL) + { + gchar *base = g_path_get_basename (filename); + gtk_label_set_text (GTK_LABEL (l->data), base); + g_free (base); + } + } + } + + if (message) + { + if (peditor->p->inited) + { + GtkWidget *box; + + box = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", + message); + gtk_dialog_run (GTK_DIALOG (box)); + gtk_widget_destroy (box); + } else { + gtk_image_set_from_stock (image, GTK_STOCK_MISSING_IMAGE, + GTK_ICON_SIZE_BUTTON); + } + g_free (message); + + return FALSE; + } + + gtk_image_set_from_pixbuf (image, pixbuf); + g_object_unref (pixbuf); + + return TRUE; +} + +static void +peditor_image_chooser_response_cb (GtkWidget *chooser, + gint response, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + gchar *filename; + + if (response == GTK_RESPONSE_CANCEL || + response == GTK_RESPONSE_DELETE_EVENT) + { + gtk_widget_destroy (chooser); + return; + } + + if (!peditor->p->inited) + return; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); + if (!(filename && peditor_image_set_filename (peditor, filename))) + { + g_free (filename); + return; + } + + value_wid = mateconf_value_new (MATECONF_VALUE_STRING); + mateconf_value_set_string (value_wid, filename); + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + + mateconf_value_free (value_wid); + mateconf_value_free (value); + g_free (filename); + gtk_widget_destroy (chooser); +} + +static void +peditor_image_chooser_update_preview_cb (GtkFileChooser *chooser, + GtkImage *preview) +{ + char *filename; + GdkPixbuf *pixbuf = NULL; + const int scale = 100; + + filename = gtk_file_chooser_get_preview_filename (chooser); + + if (filename != NULL && g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + pixbuf = gdk_pixbuf_new_from_file_at_size (filename, scale, scale, NULL); + + gtk_image_set_from_pixbuf (preview, pixbuf); + + g_free (filename); + + if (pixbuf != NULL) + g_object_unref (pixbuf); +} + +static void +peditor_image_clicked_cb (MateConfPropertyEditor *peditor, GtkButton *button) +{ + MateConfValue *value = NULL, *value_wid; + const gchar *filename; + GtkWidget *chooser, *toplevel, *preview, *preview_box; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + chooser = gtk_file_chooser_dialog_new (_("Please select an image."), + GTK_IS_WINDOW (toplevel) ? GTK_WINDOW (toplevel) + : NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("_Select"), GTK_RESPONSE_OK, + NULL); + + preview = gtk_image_new (); + + preview_box = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (preview_box), preview, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (preview_box), 6); + + gtk_widget_show_all (preview_box); + gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser), + preview_box); + gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (chooser), + TRUE); + + gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK); + gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE); + gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); + + /* need the current filename */ + if (peditor->p->changeset) + mateconf_change_set_check_value (peditor->p->changeset, peditor->p->key, &value); + + if (value) + { + /* the one we got is not a copy */ + value = mateconf_value_copy (value); + } + else + { + MateConfClient *client = mateconf_client_get_default (); + value = mateconf_client_get (client, peditor->p->key, NULL); + g_object_unref (client); + } + + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + filename = mateconf_value_get_string (value_wid); + + if (filename && strcmp (filename, "")) + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), filename); + + g_signal_connect (chooser, "update-preview", + G_CALLBACK (peditor_image_chooser_update_preview_cb), + preview); + g_signal_connect (chooser, "response", + G_CALLBACK (peditor_image_chooser_response_cb), + peditor); + + if (gtk_grab_get_current ()) + gtk_grab_add (chooser); + + gtk_widget_show (chooser); + + mateconf_value_free (value); + mateconf_value_free (value_wid); +} + +static void +peditor_image_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value, *value_wid; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + const gchar *filename; + + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + filename = mateconf_value_get_string (value_wid); + peditor_image_set_filename (peditor, filename); + mateconf_value_free (value_wid); + } +} + +GObject * +mateconf_peditor_new_image (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *button, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (button != NULL, NULL); + g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_image_value_changed, + changeset, + G_OBJECT (button), + first_property_name, + var_args, NULL); + + va_end (var_args); + + g_signal_connect_swapped (button, "clicked", + (GCallback) peditor_image_clicked_cb, peditor); + + return peditor; +} + +GObject * +mateconf_peditor_new_select_radio_with_enum (MateConfChangeSet *changeset, + const gchar *key, + GSList *radio_group, + GType enum_type, + gboolean use_nick, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + MateConfPropertyEditorEnumData *enum_data; + GtkRadioButton *first_button; + GSList *item; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (radio_group != NULL, NULL); + g_return_val_if_fail (radio_group->data != NULL, NULL); + g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_group->data), NULL); + + enum_data = g_new0 (MateConfPropertyEditorEnumData, 1); + enum_data->enum_type = enum_type; + enum_data->use_nick = use_nick; + + first_button = GTK_RADIO_BUTTON (radio_group->data); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_select_radio_value_changed, + changeset, + G_OBJECT (first_button), + first_property_name, + var_args, + "conv-to-widget-cb", + peditor_enum_conv_to_widget, + "conv-from-widget-cb", + peditor_enum_conv_from_widget, + "data", + enum_data, + "data-free-cb", + g_free, + NULL); + + va_end (var_args); + + for (item = radio_group; item != NULL; item = item->next) + g_signal_connect_swapped (item->data, "toggled", + (GCallback) peditor_select_radio_widget_changed, peditor); + + return peditor; +} + +static void +peditor_tree_view_value_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MateConfPropertyEditor *peditor) +{ + MateConfValue *value; + + if (peditor->p->changeset != NULL) + mateconf_change_set_remove (peditor->p->changeset, peditor->p->key); + + if (entry && (value = mateconf_entry_get_value (entry))) { + GtkTreeView *treeview; + GtkTreeSelection *selection; + MateConfValue *value_wid; + + treeview = GTK_TREE_VIEW (peditor->p->ui_control); + selection = gtk_tree_view_get_selection (treeview); + + value_wid = peditor->p->conv_to_widget_cb (peditor, value); + + if (value_wid != NULL) { + GtkTreePath *path = gtk_tree_path_new_from_string ( + mateconf_value_get_string (value_wid)); + gtk_tree_selection_select_path (selection, path); + gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0); + gtk_tree_path_free (path); + mateconf_value_free (value_wid); + } else { + gtk_tree_selection_unselect_all (selection); + } + } +} + +static void +peditor_tree_view_widget_changed (MateConfPropertyEditor *peditor, + GtkTreeSelection *selection) +{ + GtkTreeModel *model; + GtkTreeIter iter; + MateConfValue *value, *value_wid; + + if (!peditor->p->inited) return; + + /* we don't support GTK_SELECTION_MULTIPLE */ + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gchar *path; + + path = gtk_tree_model_get_string_from_iter (model, &iter); + value_wid = mateconf_value_new (MATECONF_VALUE_STRING); + mateconf_value_set_string (value_wid, path); + g_free (path); + } else + value_wid = NULL; + + value = peditor->p->conv_from_widget_cb (peditor, value_wid); + peditor_set_mateconf_value (peditor, peditor->p->key, value); + g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value); + + if (value_wid) + mateconf_value_free (value_wid); + if (value) + mateconf_value_free (value); +} + +GObject * +mateconf_peditor_new_tree_view (MateConfChangeSet *changeset, + const gchar *key, + GtkWidget *tree_view, + const gchar *first_property_name, + ...) +{ + GObject *peditor; + va_list var_args; + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (tree_view != NULL, NULL); + g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL); + + va_start (var_args, first_property_name); + + peditor = mateconf_peditor_new + (key, + (MateConfClientNotifyFunc) peditor_tree_view_value_changed, + changeset, + G_OBJECT (tree_view), + first_property_name, + var_args, NULL); + + va_end (var_args); + + g_signal_connect_swapped (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + "changed", + (GCallback) peditor_tree_view_widget_changed, peditor); + + return peditor; +} |