20
20
#include "gwh-settings.h"
22
24
#include <string.h>
27
#include <glib/gi18n-lib.h>
24
28
#include <glib-object.h>
25
#include <gtk/gtk.h> /* for GtkOrientation */
27
#include "gwh-enum-types.h" /* for GwhUiBrowserPosition */
30
/* sets @ptr to @value, freeing @ptr before.
32
* * ptr can be used to compute @value, assignation is done after comuptation
33
* * ptr is used twice, so it must be side-effects-free */
34
#define setptr(ptr, value) \
36
gpointer new_ptr = (value); \
42
32
struct _GwhSettingsPrivate
44
gboolean browser_auto_reload;
45
gchar *browser_last_uri;
46
GtkOrientation browser_orientation;
47
GwhBrowserPosition browser_position;
48
gchar *browser_separate_window_geometry;
49
gchar *inspector_window_geometry;
55
PROP_BROWSER_AUTO_RELOAD,
56
PROP_BROWSER_LAST_URI,
57
PROP_BROWSER_ORIENTATION,
58
PROP_BROWSER_POSITION,
59
PROP_BROWSER_SEPARATE_WINDOW_GEOMETRY,
60
PROP_INSPECTOR_WINDOW_GEOMETRY
34
GPtrArray *prop_array;
73
47
GwhSettings *self = GWH_SETTINGS (object);
76
case PROP_BROWSER_AUTO_RELOAD:
77
g_value_set_boolean (value, self->priv->browser_auto_reload);
79
case PROP_BROWSER_LAST_URI:
80
g_value_set_string (value, self->priv->browser_last_uri);
82
case PROP_BROWSER_ORIENTATION:
83
g_value_set_enum (value, self->priv->browser_orientation);
85
case PROP_BROWSER_POSITION:
86
g_value_set_enum (value, self->priv->browser_position);
88
case PROP_BROWSER_SEPARATE_WINDOW_GEOMETRY:
89
g_value_set_string (value, self->priv->browser_separate_window_geometry);
91
case PROP_INSPECTOR_WINDOW_GEOMETRY:
92
g_value_set_string (value, self->priv->inspector_window_geometry);
49
if (G_LIKELY (prop_id > 0 && prop_id <= self->priv->prop_array->len)) {
96
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
52
prop_value = g_ptr_array_index (self->priv->prop_array, prop_id - 1);
53
g_value_copy (prop_value, value);
55
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
106
65
GwhSettings *self = GWH_SETTINGS (object);
109
case PROP_BROWSER_AUTO_RELOAD:
110
self->priv->browser_auto_reload = g_value_get_boolean (value);
112
case PROP_BROWSER_LAST_URI:
113
setptr (self->priv->browser_last_uri, g_value_dup_string (value));
115
case PROP_BROWSER_ORIENTATION:
116
self->priv->browser_orientation = g_value_get_enum (value);
118
case PROP_BROWSER_POSITION:
119
self->priv->browser_position = g_value_get_enum (value);
121
case PROP_BROWSER_SEPARATE_WINDOW_GEOMETRY:
122
setptr (self->priv->browser_separate_window_geometry,
123
g_value_dup_string (value));
125
case PROP_INSPECTOR_WINDOW_GEOMETRY:
126
setptr (self->priv->inspector_window_geometry, g_value_dup_string (value));
67
if (G_LIKELY (prop_id > 0 && prop_id <= self->priv->prop_array->len)) {
130
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
70
prop_value = g_ptr_array_index (self->priv->prop_array, prop_id - 1);
71
g_value_copy (value, prop_value);
73
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
99
free_prop_item (gpointer data,
102
g_value_unset (data);
156
107
gwh_settings_finalize (GObject *object)
158
109
GwhSettings *self = GWH_SETTINGS (object);
160
self->priv->browser_auto_reload = FALSE;
161
setptr (self->priv->browser_last_uri, NULL);
162
self->priv->browser_orientation = 0;
163
self->priv->browser_position = 0;
164
setptr (self->priv->inspector_window_geometry, NULL);
111
g_ptr_array_foreach (self->priv->prop_array, free_prop_item, NULL);
112
g_ptr_array_free (self->priv->prop_array, TRUE);
113
self->priv->prop_array = NULL;
166
115
G_OBJECT_CLASS (gwh_settings_parent_class)->finalize (object);
176
125
object_class->get_property = gwh_settings_get_property;
177
126
object_class->set_property = gwh_settings_set_property;
179
g_object_class_install_property (object_class, PROP_BROWSER_AUTO_RELOAD,
180
g_param_spec_boolean ("browser-auto-reload",
181
"Browser auto reload",
182
"Whether the browser reloads itself upon document saving",
185
g_object_class_install_property (object_class, PROP_BROWSER_LAST_URI,
186
g_param_spec_string ("browser-last-uri",
188
"Last URI visited by the browser",
191
g_object_class_install_property (object_class, PROP_BROWSER_ORIENTATION,
192
g_param_spec_enum ("browser-orientation",
193
"Browser orientation",
194
"Orientation of the browser widget",
195
GTK_TYPE_ORIENTATION,
196
GTK_ORIENTATION_VERTICAL,
198
g_object_class_install_property (object_class, PROP_BROWSER_POSITION,
199
g_param_spec_enum ("browser-position",
201
"Position of the browser widget in Geany's UI",
202
GWH_TYPE_BROWSER_POSITION,
203
GWH_BROWSER_POSITION_MESSAGE_WINDOW,
205
g_object_class_install_property (object_class, PROP_BROWSER_SEPARATE_WINDOW_GEOMETRY,
206
g_param_spec_string ("browser-separate-window-geometry",
207
"Browser separate window geometry",
208
"Last geometry of the separated browser's window",
211
g_object_class_install_property (object_class, PROP_INSPECTOR_WINDOW_GEOMETRY,
212
g_param_spec_string ("inspector-window-geometry",
213
"Inspector window geometry",
214
"Last geometry of the inspector window",
218
128
g_type_class_add_private (klass, sizeof (GwhSettingsPrivate));
224
134
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GWH_TYPE_SETTINGS,
225
135
GwhSettingsPrivate);
226
self->priv->browser_auto_reload = TRUE;
227
self->priv->browser_last_uri = g_strdup ("about:blank");
228
self->priv->browser_orientation = GTK_ORIENTATION_VERTICAL;
229
self->priv->browser_position = GWH_BROWSER_POSITION_MESSAGE_WINDOW;
230
self->priv->browser_separate_window_geometry = g_strdup ("400x300");
231
self->priv->inspector_window_geometry = g_strdup ("400x300");
136
self->priv->prop_array = g_ptr_array_new ();
240
145
return g_object_new (GWH_TYPE_SETTINGS, NULL);
149
is_pspec_installed (GObject *obj,
150
const GParamSpec *pspec)
155
gboolean installed = FALSE;
157
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (obj), &n_props);
158
for (i = 0; ! installed && i < n_props; i++) {
159
installed = (pspec->value_type == pspecs[i]->value_type &&
160
strcmp (pspec->name, pspecs[i]->name) == 0);
168
gwh_settings_install_property (GwhSettings *self,
173
g_return_if_fail (GWH_IS_SETTINGS (self));
174
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
176
/* a bit hackish, but allows to install the same property twice because the
177
* class will not be destroyed if the plugin gets reloaded. safe since the
178
* object is a singleton that will never de destroyed, and the plugin is
179
* resident, so the object is still valid after a reload. */
180
if (is_pspec_installed (G_OBJECT (self), pspec)) {
184
value = g_value_init (g_malloc0 (sizeof *value), pspec->value_type);
185
switch (G_TYPE_FUNDAMENTAL (pspec->value_type)) {
186
#define HANDLE_BASIC_TYPE(NAME, Name, name) \
187
case G_TYPE_##NAME: \
188
g_value_set_##name (value, ((GParamSpec##Name*)pspec)->default_value); \
191
HANDLE_BASIC_TYPE (BOOLEAN, Boolean, boolean)
192
HANDLE_BASIC_TYPE (CHAR, Char, char)
193
HANDLE_BASIC_TYPE (UCHAR, UChar, uchar)
194
HANDLE_BASIC_TYPE (INT, Int, int)
195
HANDLE_BASIC_TYPE (UINT, UInt, uint)
196
HANDLE_BASIC_TYPE (LONG, Long, long)
197
HANDLE_BASIC_TYPE (ULONG, ULong, ulong)
198
HANDLE_BASIC_TYPE (INT64, Int64, int64)
199
HANDLE_BASIC_TYPE (UINT64, UInt64, uint64)
200
HANDLE_BASIC_TYPE (FLOAT, Float, float)
201
HANDLE_BASIC_TYPE (DOUBLE, Double, double)
202
HANDLE_BASIC_TYPE (ENUM, Enum, enum)
203
HANDLE_BASIC_TYPE (FLAGS, Flags, flags)
204
HANDLE_BASIC_TYPE (STRING, String, string)
206
#undef HANDLE_BASIC_TYPE
212
/* nothing to do with these types, default GValue is fine since they have
213
* no default value */
217
g_critical ("Unsupported property type \"%s\" for property \"%s\"",
218
G_VALUE_TYPE_NAME (value), pspec->name);
219
g_value_unset (value);
223
g_ptr_array_add (self->priv->prop_array, value);
224
g_object_class_install_property (G_OBJECT_GET_CLASS (self),
225
self->priv->prop_array->len, pspec);
244
229
get_key_and_group_from_property_name (const gchar *name,
462
/* display/edit widgets stuff */
465
* gwh_settings_widget_<type>_notify:
466
* calls user's callback with appropriate arguments
467
* gwh_settings_widget_<type>_notify_callback:
468
* a callback connected to a signal on the widget.
469
* calls gwh_settings_widget_<type>_notify
470
* gwh_settings_widget_<type>_new:
472
* gwh_settings_widget_<type>_sync:
473
* syncs widget's value with its setting
477
typedef struct _GwhSettingsWidgetNotifyData
479
GwhSettings *settings;
482
} GwhSettingsWidgetNotifyData;
486
gwh_settings_widget_boolean_notify (GObject *tbutton,
487
GwhSettingsWidgetNotifyData *data)
489
((GwhSettingsWidgetBooleanNotify)data->callback) (data->settings,
490
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tbutton)),
494
#define gwh_settings_widget_boolean_notify_callback gwh_settings_widget_boolean_notify
479
496
static GtkWidget *
480
gwh_settings_widget_new_boolean (GwhSettings *self,
497
gwh_settings_widget_boolean_new (GwhSettings *self,
481
498
const GValue *value,
482
499
GParamSpec *pspec,
483
500
gboolean *needs_label)
496
gwh_settings_widget_sync_boolean (GwhSettings *self,
500
g_object_set (self, pspec->name,
501
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)),
513
gwh_settings_widget_boolean_sync (GwhSettings *self,
515
const GValue *old_value,
518
gboolean val = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
520
if (g_value_get_boolean (old_value) != val) {
521
g_object_set (self, pspec->name, val, NULL);
526
gwh_settings_widget_enum_notify (GObject *object,
527
GwhSettingsWidgetNotifyData *data)
530
GtkComboBox *cbox = GTK_COMBO_BOX (object);
532
if (gtk_combo_box_get_active_iter (cbox, &iter)) {
535
gtk_tree_model_get (gtk_combo_box_get_model (cbox), &iter, 0, &val, -1);
536
((GwhSettingsWidgetEnumNotify)data->callback) (data->settings, val,
541
#define gwh_settings_widget_enum_notify_callback gwh_settings_widget_enum_notify
505
543
static GtkWidget *
506
gwh_settings_widget_new_enum (GwhSettings *self,
544
gwh_settings_widget_enum_new (GwhSettings *self,
507
545
const GValue *value,
508
546
GParamSpec *pspec,
509
547
gboolean *needs_label)
523
561
gtk_list_store_append (store, &iter);
524
562
gtk_list_store_set (store, &iter,
525
563
0, enum_class->values[i].value,
526
1, enum_class->values[i].value_nick,
564
1, _(enum_class->values[i].value_nick),
528
566
if (g_value_get_enum (value) == enum_class->values[i].value) {
557
596
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
558
597
gtk_tree_model_get (model, &iter, 0, &val, -1);
598
if (g_value_get_enum (old_value) != val) {
599
g_object_set (self, pspec->name, val, NULL);
605
gwh_settings_widget_int_notify (GObject *spin,
606
GwhSettingsWidgetNotifyData *data)
608
((GwhSettingsWidgetIntNotify)data->callback) (data->settings,
609
gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)),
613
#define gwh_settings_widget_int_notify_callback gwh_settings_widget_int_notify
616
gwh_settings_widget_int_new (GwhSettings *self,
619
gboolean *needs_label)
623
GParamSpecInt *pspec_int = G_PARAM_SPEC_INT (pspec);
625
adj = gtk_adjustment_new ((gdouble)g_value_get_int (value),
626
(gdouble)pspec_int->minimum,
627
(gdouble)pspec_int->maximum,
629
button = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0.0, 0);
636
gwh_settings_widget_int_sync (GwhSettings *self,
638
const GValue *old_value,
641
gint val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
643
if (g_value_get_int (old_value) != val) {
559
644
g_object_set (self, pspec->name, val, NULL);
649
gwh_settings_widget_string_notify (GObject *entry,
650
GwhSettingsWidgetNotifyData *data)
652
((GwhSettingsWidgetStringNotify)data->callback) (data->settings,
653
gtk_entry_get_text (GTK_ENTRY (entry)),
658
gwh_settings_widget_string_notify_callback (GObject *object,
660
GwhSettingsWidgetNotifyData *data)
662
gwh_settings_widget_string_notify (object, data);
563
665
static GtkWidget *
564
gwh_settings_widget_new_string (GwhSettings *self,
666
gwh_settings_widget_string_new (GwhSettings *self,
565
667
const GValue *value,
566
668
GParamSpec *pspec,
567
669
gboolean *needs_label)
579
gwh_settings_widget_sync_string (GwhSettings *self,
681
gwh_settings_widget_string_sync (GwhSettings *self,
683
const GValue *old_value,
583
g_object_set (self, pspec->name, gtk_entry_get_text (GTK_ENTRY (widget)),
686
const gchar *val = gtk_entry_get_text (GTK_ENTRY (widget));
687
const gchar *old_val = g_value_get_string (old_value);
689
if (g_strcmp0 (old_val, val) != 0) {
690
g_object_set (self, pspec->name, val, NULL);
588
695
#define KEY_PSPEC "gwh-settings-configure-pspec"
589
696
#define KEY_WIDGET "gwh-settings-configure-widget"
699
* gwh_settings_widget_new_full:
700
* @self: A GwhSettings object
701
* @prop_name: the name of the setting for which create a widget
702
* @setting_changed_callback: a callback to be called when the widget's value
703
* changes, or %NULL. The type of the callback
704
* is GwhSettingsWidget*Notify, depending of the
706
* @user_data: user data to pass to @callback
707
* @notify_flags: notification flags
709
* Creates a widgets to configure the value of a setting @prop_name.
710
* This setting will not be changed automatically, you'll need to call
711
* gwh_settings_widget_sync() when you want to synchronize the widget's value to
714
* Returns: A #GtkWidget that displays and edit @prop_name.
592
gwh_settings_widget_new (GwhSettings *self,
593
const gchar *prop_name)
717
gwh_settings_widget_new_full (GwhSettings *self,
718
const gchar *prop_name,
719
GCallback setting_changed_callback,
721
GwhSettingsNotifyFlags notify_flags)
595
723
GtkWidget *widget = NULL;
596
724
GParamSpec *pspec;
605
733
g_value_init (&value, pspec->value_type);
606
734
g_object_get_property (G_OBJECT (self), prop_name, &value);
607
735
switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (&value))) {
608
#define HANDLE_TYPE(T, h) \
609
case T: widget = ((h) (self, &value, pspec, &needs_label)); break;
736
#define HANDLE_TYPE(T, t, signal) \
738
widget = gwh_settings_widget_##t##_new (self, &value, pspec, \
740
if (setting_changed_callback) { \
741
GwhSettingsWidgetNotifyData *data = g_malloc (sizeof *data); \
743
data->settings = self; \
744
data->callback = setting_changed_callback; \
745
data->user_data = user_data; \
746
g_signal_connect_data (widget, signal, \
747
G_CALLBACK (gwh_settings_widget_##t##_notify_callback),\
748
data, (GClosureNotify)g_free, 0); \
749
if (notify_flags & GWH_SETTINGS_NOTIFY_ON_CONNEXION) { \
750
gwh_settings_widget_##t##_notify (G_OBJECT (widget), data); \
611
HANDLE_TYPE (G_TYPE_BOOLEAN, gwh_settings_widget_new_boolean)
612
HANDLE_TYPE (G_TYPE_ENUM, gwh_settings_widget_new_enum)
613
HANDLE_TYPE (G_TYPE_STRING, gwh_settings_widget_new_string)
755
HANDLE_TYPE (BOOLEAN, boolean, "toggled")
756
HANDLE_TYPE (ENUM, enum, "changed")
757
HANDLE_TYPE (INT, int, "value-changed")
758
HANDLE_TYPE (STRING, string, "notify::text")
615
760
#undef HANDLE_TYPE
629
774
box = gtk_hbox_new (FALSE, 6);
630
label = g_strdup_printf ("%s:", g_param_spec_get_nick (pspec));
775
label = g_strdup_printf (_("%s:"), g_param_spec_get_nick (pspec));
631
776
gtk_box_pack_start (GTK_BOX (box), gtk_label_new (label), FALSE, TRUE, 0);
633
778
gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0);
648
gwh_settings_widget_sync (GwhSettings *self,
793
gwh_settings_widget_new (GwhSettings *self,
794
const gchar *prop_name)
796
return gwh_settings_widget_new_full (self, prop_name, NULL, NULL, 0);
800
gwh_settings_widget_sync_internal (GwhSettings *self,
651
803
GParamSpec *pspec;
653
g_return_if_fail (GWH_IS_SETTINGS (self));
654
g_return_if_fail (G_IS_OBJECT (widget));
806
g_return_val_if_fail (G_IS_OBJECT (widget), FALSE);
656
808
widget = g_object_get_data (G_OBJECT (widget), KEY_WIDGET);
657
g_return_if_fail (GTK_IS_WIDGET (widget));
809
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
658
810
pspec = g_object_get_data (G_OBJECT (widget), KEY_PSPEC);
659
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
811
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
812
g_value_init (&value, pspec->value_type);
813
g_object_get_property (G_OBJECT (self), pspec->name, &value);
660
814
switch (G_TYPE_FUNDAMENTAL (pspec->value_type)) {
661
#define HANDLE_TYPE(T, h) case T: (h) (self, pspec, widget); break;
815
#define HANDLE_TYPE(T, t) \
817
gwh_settings_widget_##t##_sync (self, pspec, &value, widget); \
663
HANDLE_TYPE (G_TYPE_BOOLEAN, gwh_settings_widget_sync_boolean)
664
HANDLE_TYPE (G_TYPE_ENUM, gwh_settings_widget_sync_enum)
665
HANDLE_TYPE (G_TYPE_STRING, gwh_settings_widget_sync_string)
820
HANDLE_TYPE (BOOLEAN, boolean)
821
HANDLE_TYPE (ENUM, enum)
822
HANDLE_TYPE (INT, int)
823
HANDLE_TYPE (STRING, string)
667
825
#undef HANDLE_TYPE
670
828
g_critical ("Unsupported property type \"%s\"",
671
829
g_type_name (pspec->value_type));
831
g_value_unset (&value);
837
* gwh_settings_widget_sync_v:
838
* @self: A #GwhSettings object
839
* @...: a %NULL-terminated list of widgets to sync
841
* Same as gwh_settings_widget_sync() but emits notifications only after all
842
* widgets got synchronized.
845
gwh_settings_widget_sync_v (GwhSettings *self,
851
g_return_if_fail (GWH_IS_SETTINGS (self));
853
g_object_freeze_notify (G_OBJECT (self));
855
while ((widget = va_arg (ap, GtkWidget*))) {
856
if (! gwh_settings_widget_sync_internal (self, widget)) {
861
g_object_thaw_notify (G_OBJECT (self));
865
gwh_settings_widget_sync (GwhSettings *self,
868
g_return_if_fail (GWH_IS_SETTINGS (self));
870
gwh_settings_widget_sync_internal (self, widget);