[gtk] Replace stateful actions by property actions
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk] Replace stateful actions by property actions
- Date: Sat, 22 Jun 2019 21:05:21 +0000 (UTC)
commit d1f4068b9471184bd431f04b87c3201fd721d898
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Jun 22 20:18:05 2019 +0000
Replace stateful actions by property actions
The only cases of stateful actions we've seen
so far have been boolean properties, and we
don't really want to add much state handling
API, so lets just go with property actions
for now.
Adapt the only user in GtkText.
docs/reference/gtk/gtk4-sections.txt | 5 +-
gtk/gsettings-mapping.c | 592 +++++++++++++++++++++++++++++++++++
gtk/gsettings-mapping.h | 34 ++
gtk/gtkactionmuxer.c | 174 +++++++++-
gtk/gtkactionmuxerprivate.h | 9 +-
gtk/gtktext.c | 48 +--
gtk/gtkwidget.c | 175 ++++++-----
gtk/gtkwidget.h | 46 +--
gtk/meson.build | 1 +
9 files changed, 899 insertions(+), 185 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index cfb88c7efd..8f3d7a9f02 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -4630,13 +4630,10 @@ gtk_widget_insert_action_group
gtk_widget_activate_action
gtk_widget_activate_default
GtkWidgetActionActivateFunc
-GtkWidgetActionSetStateFunc
-GtkWidgetActionGetStateFunc
gtk_widget_class_install_action
-gtk_widget_class_install_stateful_action
+gtk_widget_class_install_property_action
gtk_widget_class_query_action
gtk_widget_action_enabled_changed
-gtk_widget_action_state_changed
<SUBSECTION Standard>
GTK_WIDGET
diff --git a/gtk/gsettings-mapping.c b/gtk/gsettings-mapping.c
new file mode 100644
index 0000000000..8c64b02a50
--- /dev/null
+++ b/gtk/gsettings-mapping.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright © 2010 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Vincent Untz <vuntz gnome org>
+ */
+
+#include "config.h"
+
+#include "gsettings-mapping.h"
+
+static GVariant *
+g_settings_set_mapping_int (const GValue *value,
+ const GVariantType *expected_type)
+{
+ GVariant *variant = NULL;
+ gint64 l;
+
+ if (G_VALUE_HOLDS_INT (value))
+ l = g_value_get_int (value);
+ else if (G_VALUE_HOLDS_INT64 (value))
+ l = g_value_get_int64 (value);
+ else
+ return NULL;
+
+ if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
+ {
+ if (G_MININT16 <= l && l <= G_MAXINT16)
+ variant = g_variant_new_int16 ((gint16) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
+ {
+ if (0 <= l && l <= G_MAXUINT16)
+ variant = g_variant_new_uint16 ((guint16) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
+ {
+ if (G_MININT32 <= l && l <= G_MAXINT32)
+ variant = g_variant_new_int32 ((gint) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
+ {
+ if (0 <= l && l <= G_MAXUINT32)
+ variant = g_variant_new_uint32 ((guint) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
+ {
+ if (G_MININT64 <= l && l <= G_MAXINT64)
+ variant = g_variant_new_int64 ((gint64) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
+ {
+ if (0 <= l && l <= G_MAXUINT64)
+ variant = g_variant_new_uint64 ((guint64) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
+ {
+ if (0 <= l && l <= G_MAXUINT32)
+ variant = g_variant_new_handle ((guint) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
+ variant = g_variant_new_double ((gdouble) l);
+
+ return variant;
+}
+
+static GVariant *
+g_settings_set_mapping_float (const GValue *value,
+ const GVariantType *expected_type)
+{
+ GVariant *variant = NULL;
+ gdouble d;
+ gint64 l;
+
+ if (G_VALUE_HOLDS_DOUBLE (value))
+ d = g_value_get_double (value);
+ else
+ return NULL;
+
+ l = (gint64) d;
+ if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
+ {
+ if (G_MININT16 <= l && l <= G_MAXINT16)
+ variant = g_variant_new_int16 ((gint16) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
+ {
+ if (0 <= l && l <= G_MAXUINT16)
+ variant = g_variant_new_uint16 ((guint16) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
+ {
+ if (G_MININT32 <= l && l <= G_MAXINT32)
+ variant = g_variant_new_int32 ((gint) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
+ {
+ if (0 <= l && l <= G_MAXUINT32)
+ variant = g_variant_new_uint32 ((guint) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
+ {
+ if (G_MININT64 <= l && l <= G_MAXINT64)
+ variant = g_variant_new_int64 ((gint64) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
+ {
+ if (0 <= l && l <= G_MAXUINT64)
+ variant = g_variant_new_uint64 ((guint64) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
+ {
+ if (0 <= l && l <= G_MAXUINT32)
+ variant = g_variant_new_handle ((guint) l);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
+ variant = g_variant_new_double ((gdouble) d);
+
+ return variant;
+}
+static GVariant *
+g_settings_set_mapping_unsigned_int (const GValue *value,
+ const GVariantType *expected_type)
+{
+ GVariant *variant = NULL;
+ guint64 u;
+
+ if (G_VALUE_HOLDS_UINT (value))
+ u = g_value_get_uint (value);
+ else if (G_VALUE_HOLDS_UINT64 (value))
+ u = g_value_get_uint64 (value);
+ else
+ return NULL;
+
+ if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
+ {
+ if (u <= G_MAXINT16)
+ variant = g_variant_new_int16 ((gint16) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
+ {
+ if (u <= G_MAXUINT16)
+ variant = g_variant_new_uint16 ((guint16) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
+ {
+ if (u <= G_MAXINT32)
+ variant = g_variant_new_int32 ((gint) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
+ {
+ if (u <= G_MAXUINT32)
+ variant = g_variant_new_uint32 ((guint) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
+ {
+ if (u <= G_MAXINT64)
+ variant = g_variant_new_int64 ((gint64) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
+ {
+ if (u <= G_MAXUINT64)
+ variant = g_variant_new_uint64 ((guint64) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
+ {
+ if (u <= G_MAXUINT32)
+ variant = g_variant_new_handle ((guint) u);
+ }
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
+ variant = g_variant_new_double ((gdouble) u);
+
+ return variant;
+}
+
+static gboolean
+g_settings_get_mapping_int (GValue *value,
+ GVariant *variant)
+{
+ const GVariantType *type;
+ gint64 l;
+
+ type = g_variant_get_type (variant);
+
+ if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
+ l = g_variant_get_int16 (variant);
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
+ l = g_variant_get_int32 (variant);
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
+ l = g_variant_get_int64 (variant);
+ else
+ return FALSE;
+
+ if (G_VALUE_HOLDS_INT (value))
+ {
+ g_value_set_int (value, l);
+ return (G_MININT32 <= l && l <= G_MAXINT32);
+ }
+ else if (G_VALUE_HOLDS_UINT (value))
+ {
+ g_value_set_uint (value, l);
+ return (0 <= l && l <= G_MAXUINT32);
+ }
+ else if (G_VALUE_HOLDS_INT64 (value))
+ {
+ g_value_set_int64 (value, l);
+ return (G_MININT64 <= l && l <= G_MAXINT64);
+ }
+ else if (G_VALUE_HOLDS_UINT64 (value))
+ {
+ g_value_set_uint64 (value, l);
+ return (0 <= l && l <= G_MAXUINT64);
+ }
+ else if (G_VALUE_HOLDS_DOUBLE (value))
+ {
+ g_value_set_double (value, l);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+g_settings_get_mapping_float (GValue *value,
+ GVariant *variant)
+{
+ const GVariantType *type;
+ gdouble d;
+ gint64 l;
+
+ type = g_variant_get_type (variant);
+
+ if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
+ d = g_variant_get_double (variant);
+ else
+ return FALSE;
+
+ l = (gint64)d;
+ if (G_VALUE_HOLDS_INT (value))
+ {
+ g_value_set_int (value, l);
+ return (G_MININT32 <= l && l <= G_MAXINT32);
+ }
+ else if (G_VALUE_HOLDS_UINT (value))
+ {
+ g_value_set_uint (value, l);
+ return (0 <= l && l <= G_MAXUINT32);
+ }
+ else if (G_VALUE_HOLDS_INT64 (value))
+ {
+ g_value_set_int64 (value, l);
+ return (G_MININT64 <= l && l <= G_MAXINT64);
+ }
+ else if (G_VALUE_HOLDS_UINT64 (value))
+ {
+ g_value_set_uint64 (value, l);
+ return (0 <= l && l <= G_MAXUINT64);
+ }
+ else if (G_VALUE_HOLDS_DOUBLE (value))
+ {
+ g_value_set_double (value, d);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+static gboolean
+g_settings_get_mapping_unsigned_int (GValue *value,
+ GVariant *variant)
+{
+ const GVariantType *type;
+ guint64 u;
+
+ type = g_variant_get_type (variant);
+
+ if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
+ u = g_variant_get_uint16 (variant);
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
+ u = g_variant_get_uint32 (variant);
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
+ u = g_variant_get_uint64 (variant);
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
+ u = g_variant_get_handle (variant);
+ else
+ return FALSE;
+
+ if (G_VALUE_HOLDS_INT (value))
+ {
+ g_value_set_int (value, u);
+ return (u <= G_MAXINT32);
+ }
+ else if (G_VALUE_HOLDS_UINT (value))
+ {
+ g_value_set_uint (value, u);
+ return (u <= G_MAXUINT32);
+ }
+ else if (G_VALUE_HOLDS_INT64 (value))
+ {
+ g_value_set_int64 (value, u);
+ return (u <= G_MAXINT64);
+ }
+ else if (G_VALUE_HOLDS_UINT64 (value))
+ {
+ g_value_set_uint64 (value, u);
+ return (u <= G_MAXUINT64);
+ }
+ else if (G_VALUE_HOLDS_DOUBLE (value))
+ {
+ g_value_set_double (value, u);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+GVariant *
+g_settings_set_mapping (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ gchar *type_string;
+
+ if (G_VALUE_HOLDS_BOOLEAN (value))
+ {
+ if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BOOLEAN))
+ return g_variant_new_boolean (g_value_get_boolean (value));
+ }
+
+ else if (G_VALUE_HOLDS_CHAR (value) ||
+ G_VALUE_HOLDS_UCHAR (value))
+ {
+ if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTE))
+ {
+ if (G_VALUE_HOLDS_CHAR (value))
+ return g_variant_new_byte (g_value_get_schar (value));
+ else
+ return g_variant_new_byte (g_value_get_uchar (value));
+ }
+ }
+
+ else if (G_VALUE_HOLDS_INT (value) ||
+ G_VALUE_HOLDS_INT64 (value))
+ return g_settings_set_mapping_int (value, expected_type);
+
+ else if (G_VALUE_HOLDS_DOUBLE (value))
+ return g_settings_set_mapping_float (value, expected_type);
+
+ else if (G_VALUE_HOLDS_UINT (value) ||
+ G_VALUE_HOLDS_UINT64 (value))
+ return g_settings_set_mapping_unsigned_int (value, expected_type);
+
+ else if (G_VALUE_HOLDS_STRING (value))
+ {
+ if (g_value_get_string (value) == NULL)
+ return NULL;
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING))
+ return g_variant_new_string (g_value_get_string (value));
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTESTRING))
+ return g_variant_new_bytestring (g_value_get_string (value));
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH))
+ return g_variant_new_object_path (g_value_get_string (value));
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE))
+ return g_variant_new_signature (g_value_get_string (value));
+ }
+
+ else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
+ {
+ if (g_value_get_boxed (value) == NULL)
+ return NULL;
+ return g_variant_new_strv ((const gchar **) g_value_get_boxed (value),
+ -1);
+ }
+
+ else if (G_VALUE_HOLDS_ENUM (value))
+ {
+ GEnumValue *enumval;
+ GEnumClass *eclass;
+
+ /* GParamSpecEnum holds a ref on the class so we just peek... */
+ eclass = g_type_class_peek (G_VALUE_TYPE (value));
+ enumval = g_enum_get_value (eclass, g_value_get_enum (value));
+
+ if (enumval)
+ return g_variant_new_string (enumval->value_nick);
+ else
+ return NULL;
+ }
+
+ else if (G_VALUE_HOLDS_FLAGS (value))
+ {
+ GVariantBuilder builder;
+ GFlagsValue *flagsval;
+ GFlagsClass *fclass;
+ guint flags;
+
+ fclass = g_type_class_peek (G_VALUE_TYPE (value));
+ flags = g_value_get_flags (value);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+ while (flags)
+ {
+ flagsval = g_flags_get_first_value (fclass, flags);
+
+ if (flagsval == NULL)
+ {
+ g_variant_builder_clear (&builder);
+ return NULL;
+ }
+
+ g_variant_builder_add (&builder, "s", flagsval->value_nick);
+ flags &= ~flagsval->value;
+ }
+
+ return g_variant_builder_end (&builder);
+ }
+
+ type_string = g_variant_type_dup_string (expected_type);
+ g_critical ("No GSettings bind handler for type \"%s\".", type_string);
+ g_free (type_string);
+
+ return NULL;
+}
+
+gboolean
+g_settings_get_mapping (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
+ {
+ if (!G_VALUE_HOLDS_BOOLEAN (value))
+ return FALSE;
+ g_value_set_boolean (value, g_variant_get_boolean (variant));
+ return TRUE;
+ }
+
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
+ {
+ if (G_VALUE_HOLDS_UCHAR (value))
+ g_value_set_uchar (value, g_variant_get_byte (variant));
+ else if (G_VALUE_HOLDS_CHAR (value))
+ g_value_set_schar (value, (gint8)g_variant_get_byte (variant));
+ else
+ return FALSE;
+ return TRUE;
+ }
+
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64))
+ return g_settings_get_mapping_int (value, variant);
+
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
+ return g_settings_get_mapping_float (value, variant);
+
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
+ return g_settings_get_mapping_unsigned_int (value, variant);
+
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) ||
+ g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
+ {
+ if (G_VALUE_HOLDS_STRING (value))
+ {
+ g_value_set_string (value, g_variant_get_string (variant, NULL));
+ return TRUE;
+ }
+
+ else if (G_VALUE_HOLDS_ENUM (value))
+ {
+ GEnumClass *eclass;
+ GEnumValue *evalue;
+ const gchar *nick;
+
+ /* GParamSpecEnum holds a ref on the class so we just peek... */
+ eclass = g_type_class_peek (G_VALUE_TYPE (value));
+ nick = g_variant_get_string (variant, NULL);
+ evalue = g_enum_get_value_by_nick (eclass, nick);
+
+ if (evalue)
+ {
+ g_value_set_enum (value, evalue->value);
+ return TRUE;
+ }
+
+ g_warning ("Unable to look up enum nick ‘%s’ via GType", nick);
+ return FALSE;
+ }
+ }
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("as")))
+ {
+ if (G_VALUE_HOLDS (value, G_TYPE_STRV))
+ {
+ g_value_take_boxed (value, g_variant_dup_strv (variant, NULL));
+ return TRUE;
+ }
+
+ else if (G_VALUE_HOLDS_FLAGS (value))
+ {
+ GFlagsClass *fclass;
+ GFlagsValue *fvalue;
+ const gchar *nick;
+ GVariantIter iter;
+ guint flags = 0;
+
+ fclass = g_type_class_peek (G_VALUE_TYPE (value));
+
+ g_variant_iter_init (&iter, variant);
+ while (g_variant_iter_next (&iter, "&s", &nick))
+ {
+ fvalue = g_flags_get_value_by_nick (fclass, nick);
+
+ if (fvalue)
+ flags |= fvalue->value;
+
+ else
+ {
+ g_warning ("Unable to lookup flags nick '%s' via GType",
+ nick);
+ return FALSE;
+ }
+ }
+
+ g_value_set_flags (value, flags);
+ return TRUE;
+ }
+ }
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING))
+ {
+ g_value_set_string (value, g_variant_get_bytestring (variant));
+ return TRUE;
+ }
+
+ g_critical ("No GSettings bind handler for type \"%s\".",
+ g_variant_get_type_string (variant));
+
+ return FALSE;
+}
+
+gboolean
+g_settings_mapping_is_compatible (GType gvalue_type,
+ const GVariantType *variant_type)
+{
+ gboolean ok = FALSE;
+
+ if (gvalue_type == G_TYPE_BOOLEAN)
+ ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN);
+ else if (gvalue_type == G_TYPE_CHAR ||
+ gvalue_type == G_TYPE_UCHAR)
+ ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE);
+ else if (gvalue_type == G_TYPE_INT ||
+ gvalue_type == G_TYPE_UINT ||
+ gvalue_type == G_TYPE_INT64 ||
+ gvalue_type == G_TYPE_UINT64 ||
+ gvalue_type == G_TYPE_DOUBLE)
+ ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_HANDLE) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE));
+ else if (gvalue_type == G_TYPE_STRING)
+ ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE ("ay")) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) ||
+ g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE));
+ else if (gvalue_type == G_TYPE_STRV)
+ ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE ("as"));
+ else if (G_TYPE_IS_ENUM (gvalue_type))
+ ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING);
+ else if (G_TYPE_IS_FLAGS (gvalue_type))
+ ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE ("as"));
+
+ return ok;
+}
diff --git a/gtk/gsettings-mapping.h b/gtk/gsettings-mapping.h
new file mode 100644
index 0000000000..8a26684bb6
--- /dev/null
+++ b/gtk/gsettings-mapping.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2010 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Vincent Untz <vuntz gnome org>
+ */
+
+#ifndef __G_SETTINGS_MAPPING_H__
+#define __G_SETTINGS_MAPPING_H__
+
+#include <glib-object.h>
+
+GVariant * g_settings_set_mapping (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data);
+gboolean g_settings_get_mapping (GValue *value,
+ GVariant *variant,
+ gpointer user_data);
+gboolean g_settings_mapping_is_compatible (GType gvalue_type,
+ const GVariantType *variant_type);
+
+#endif /* __G_SETTINGS_MAPPING_H__ */
diff --git a/gtk/gtkactionmuxer.c b/gtk/gtkactionmuxer.c
index 515f93f6db..f74a65367a 100644
--- a/gtk/gtkactionmuxer.c
+++ b/gtk/gtkactionmuxer.c
@@ -26,6 +26,7 @@
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkwidget.h"
+#include "gsettings-mapping.h"
#include <string.h>
@@ -420,6 +421,145 @@ gtk_action_muxer_parent_primary_accel_changed (GtkActionMuxer *parent,
gtk_action_muxer_primary_accel_changed (muxer, action_name, action_and_target);
}
+static GVariant *
+prop_action_get_state (GtkWidget *widget,
+ GtkWidgetAction *action)
+{
+ GValue value = G_VALUE_INIT;
+ GVariant *result;
+
+ g_value_init (&value, action->pspec->value_type);
+ g_object_get_property (G_OBJECT (widget), action->pspec->name, &value);
+
+ result = g_settings_set_mapping (&value, action->state_type, NULL);
+ g_value_unset (&value);
+
+ return g_variant_ref_sink (result);
+}
+
+static GVariant *
+prop_action_get_state_hint (GtkWidget *widget,
+ GtkWidgetAction *action)
+{
+ if (action->pspec->value_type == G_TYPE_INT)
+ {
+ GParamSpecInt *pspec = (GParamSpecInt *)action->pspec;
+ return g_variant_new ("(ii)", pspec->minimum, pspec->maximum);
+ }
+ else if (action->pspec->value_type == G_TYPE_UINT)
+ {
+ GParamSpecUInt *pspec = (GParamSpecUInt *)action->pspec;
+ return g_variant_new ("(uu)", pspec->minimum, pspec->maximum);
+ }
+ else if (action->pspec->value_type == G_TYPE_FLOAT)
+ {
+ GParamSpecFloat *pspec = (GParamSpecFloat *)action->pspec;
+ return g_variant_new ("(dd)", (double)pspec->minimum, (double)pspec->maximum);
+ }
+ else if (action->pspec->value_type == G_TYPE_DOUBLE)
+ {
+ GParamSpecDouble *pspec = (GParamSpecDouble *)action->pspec;
+ return g_variant_new ("(dd)", pspec->minimum, pspec->maximum);
+ }
+
+ return NULL;
+}
+
+static void
+prop_action_set_state (GtkWidget *widget,
+ GtkWidgetAction *action,
+ GVariant *state)
+{
+ GValue value = G_VALUE_INIT;
+
+ g_value_init (&value, action->pspec->value_type);
+ g_settings_get_mapping (&value, state, NULL);
+
+ g_object_set_property (G_OBJECT (widget), action->pspec->name, &value);
+ g_value_unset (&value);
+}
+
+static void
+prop_action_activate (GtkWidget *widget,
+ GtkWidgetAction *action,
+ GVariant *parameter)
+{
+ if (action->pspec->value_type == G_TYPE_BOOLEAN)
+ {
+ gboolean value;
+
+ g_return_if_fail (parameter == NULL);
+
+ g_object_get (G_OBJECT (widget), action->pspec->name, &value, NULL);
+ value = !value;
+ g_object_set (G_OBJECT (widget), action->pspec->name, value, NULL);
+ }
+ else
+ {
+ g_return_if_fail (parameter != NULL && g_variant_is_of_type (parameter, action->state_type));
+
+ prop_action_set_state (widget, action, parameter);
+ }
+}
+
+static void
+prop_action_notify (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GtkActionMuxer *muxer = user_data;
+ int i;
+ GtkWidgetAction *action = NULL;
+ GVariant *state;
+
+ g_assert ((GObject *)muxer->widget == object);
+
+ for (i = 0; i < muxer->widget_actions->len; i++)
+ {
+ action = g_ptr_array_index (muxer->widget_actions, i);
+ if (action->pspec == pspec)
+ break;
+ action = NULL;
+ }
+
+ g_assert (action != NULL);
+
+ state = prop_action_get_state (muxer->widget, action);
+ gtk_action_muxer_action_state_changed (muxer, action->name, state);
+ g_variant_unref (state);
+}
+
+static void
+prop_actions_connect (GtkActionMuxer *muxer)
+{
+ int i;
+
+ if (!muxer->widget || !muxer->widget_actions)
+ return;
+
+ for (i = 0; i < muxer->widget_actions->len; i++)
+ {
+ GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
+ char *detailed;
+
+ if (!action->pspec)
+ continue;
+
+ detailed = g_strconcat ("notify::", action->pspec->name, NULL);
+ g_signal_connect (muxer->widget, detailed,
+ G_CALLBACK (prop_action_notify), muxer);
+ g_free (detailed);
+ }
+}
+
+static void
+prop_actions_disconnect (GtkActionMuxer *muxer)
+{
+ if (muxer->widget)
+ g_signal_handlers_disconnect_by_func (muxer->widget,
+ prop_action_notify, muxer);
+}
+
static gboolean
gtk_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
@@ -454,16 +594,12 @@ gtk_action_muxer_query_action (GActionGroup *action_group,
if (state)
*state = NULL;
- if (action->get_state)
+ if (action->pspec)
{
- GVariant *s;
-
- s = g_variant_ref_sink (action->get_state (muxer->widget, action->name));
-
if (state)
- *state = g_variant_ref (s);
-
- g_variant_unref (s);
+ *state = prop_action_get_state (muxer->widget, action);
+ if (state_hint)
+ *state_hint = prop_action_get_state_hint (muxer->widget, action);
}
return TRUE;
@@ -503,7 +639,10 @@ gtk_action_muxer_activate_action (GActionGroup *action_group,
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0)
{
- action->activate (muxer->widget, action->name, parameter);
+ if (action->activate)
+ action->activate (muxer->widget, action->name, parameter);
+ else if (action->pspec)
+ prop_action_activate (muxer->widget, action, parameter);
return;
}
@@ -536,8 +675,8 @@ gtk_action_muxer_change_action_state (GActionGroup *action_group,
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0)
{
- if (action->set_state)
- action->set_state (muxer->widget, action->name, state);
+ if (action->pspec)
+ prop_action_set_state (muxer->widget, action, state);
return;
}
@@ -668,6 +807,8 @@ gtk_action_muxer_dispose (GObject *object)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
+ prop_actions_disconnect (muxer);
+
if (muxer->parent)
{
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
@@ -685,6 +826,16 @@ gtk_action_muxer_dispose (GObject *object)
->dispose (object);
}
+static void
+gtk_action_muxer_constructed (GObject *object)
+{
+ GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
+
+ prop_actions_connect (muxer);
+
+ G_OBJECT_CLASS (gtk_action_muxer_parent_class)->constructed (object);
+}
+
static void
gtk_action_muxer_get_property (GObject *object,
guint property_id,
@@ -775,6 +926,7 @@ gtk_action_muxer_class_init (GObjectClass *class)
{
class->get_property = gtk_action_muxer_get_property;
class->set_property = gtk_action_muxer_set_property;
+ class->constructed = gtk_action_muxer_constructed;
class->finalize = gtk_action_muxer_finalize;
class->dispose = gtk_action_muxer_dispose;
diff --git a/gtk/gtkactionmuxerprivate.h b/gtk/gtkactionmuxerprivate.h
index b1b8cef9cc..44dbb8a404 100644
--- a/gtk/gtkactionmuxerprivate.h
+++ b/gtk/gtkactionmuxerprivate.h
@@ -33,14 +33,13 @@ G_BEGIN_DECLS
typedef struct {
char *name;
-
GType owner;
- GVariantType *parameter_type;
- GVariantType *state_type;
+ const GVariantType *parameter_type;
GtkWidgetActionActivateFunc activate;
- GtkWidgetActionSetStateFunc set_state;
- GtkWidgetActionGetStateFunc get_state;
+
+ const GVariantType *state_type;
+ GParamSpec *pspec;
} GtkWidgetAction;
typedef struct _GtkActionMuxer GtkActionMuxer;
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 943f0d0cbf..7e91178259 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -563,15 +563,6 @@ static void gtk_text_activate_selection_select_all (GtkWidget *widget,
static void gtk_text_activate_misc_insert_emoji (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
-static void gtk_text_activate_misc_toggle_visibility (GtkWidget *widget,
- const char *action_name,
- GVariant *parameter);
-
-static void gtk_text_set_misc_toggle_visibility (GtkWidget *widget,
- const char *action_name,
- GVariant *state);
-static GVariant *gtk_text_get_misc_toggle_visibility (GtkWidget *widget,
- const char *action_name);
/* GtkTextContent implementation
*/
@@ -1375,11 +1366,9 @@ gtk_text_class_init (GtkTextClass *class)
gtk_text_activate_selection_select_all);
gtk_widget_class_install_action (widget_class, "misc.insert-emoji", NULL,
gtk_text_activate_misc_insert_emoji);
- gtk_widget_class_install_stateful_action (widget_class, "misc.toggle-visibility", NULL,
- gtk_text_activate_misc_toggle_visibility,
- "b",
- gtk_text_set_misc_toggle_visibility,
- gtk_text_get_misc_toggle_visibility);
+ gtk_widget_class_install_property_action (widget_class,
+ "misc.toggle-visibility",
+ "visibility");
}
static void
@@ -5313,8 +5302,6 @@ gtk_text_set_visibility (GtkText *self,
gtk_text_recompute (self);
gtk_text_update_clipboard_actions (self);
- gtk_widget_action_state_changed (GTK_WIDGET (self), "misc.toggle-visibility",
- g_variant_new_boolean (visible));
}
}
@@ -5718,35 +5705,6 @@ gtk_text_activate_misc_insert_emoji (GtkWidget *widget,
hide_selection_bubble (self);
}
-static void
-gtk_text_activate_misc_toggle_visibility (GtkWidget *widget,
- const char *action_name,
- GVariant *parameter)
-{
- GtkText *self = GTK_TEXT (widget);
- gtk_text_set_visibility (self, !gtk_text_get_visibility (self));
-}
-
-static GVariant *
-gtk_text_get_misc_toggle_visibility (GtkWidget *widget,
- const char *action_name)
-{
- GtkText *self = GTK_TEXT (widget);
- DisplayMode mode = gtk_text_get_display_mode (self);
-
- return g_variant_new_boolean (mode == DISPLAY_NORMAL);
-}
-
-static void
-gtk_text_set_misc_toggle_visibility (GtkWidget *widget,
- const char *action_name,
- GVariant *state)
-{
- GtkText *self = GTK_TEXT (widget);
- gboolean visible = g_variant_get_boolean (state);
- gtk_text_set_visibility (self, visible);
-}
-
static void
gtk_text_update_clipboard_actions (GtkText *self)
{
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 16d86cfbb7..926d61fa00 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -13430,6 +13430,37 @@ gtk_widget_should_layout (GtkWidget *widget)
return TRUE;
}
+static void
+gtk_widget_class_add_action (GtkWidgetClass *widget_class,
+ GtkWidgetAction *action)
+{
+ GtkWidgetClassPrivate *priv = widget_class->priv;
+
+ if (priv->actions == NULL)
+ priv->actions = g_ptr_array_new ();
+ else if (GTK_IS_WIDGET_CLASS (&widget_class->parent_class))
+ {
+ GtkWidgetClass *parent_class = GTK_WIDGET_CLASS (&widget_class->parent_class);
+ GtkWidgetClassPrivate *parent_priv = parent_class->priv;
+ GPtrArray *parent_actions = parent_priv->actions;
+
+ if (priv->actions == parent_actions)
+ {
+ int i;
+
+ priv->actions = g_ptr_array_new ();
+ for (i = 0; i < parent_actions->len; i++)
+ g_ptr_array_add (priv->actions, g_ptr_array_index (parent_actions, i));
+ }
+ }
+
+ GTK_NOTE(ACTIONS, g_message ("%sClass: Adding %s action\n",
+ g_type_name (G_TYPE_FROM_CLASS (widget_class)),
+ action->name));
+
+ g_ptr_array_add (priv->actions, action);
+}
+
/*
* gtk_widget_class_install_action:
* @widget_class: a #GtkWidgetClass
@@ -13450,76 +13481,89 @@ gtk_widget_class_install_action (GtkWidgetClass *widget_class,
const char *parameter_type,
GtkWidgetActionActivateFunc activate)
{
- gtk_widget_class_install_stateful_action (widget_class, action_name,
- parameter_type, activate,
- NULL, NULL, NULL);
+ GtkWidgetAction *action;
+
+ action = g_new0 (GtkWidgetAction, 1);
+ action->owner = G_TYPE_FROM_CLASS (widget_class);
+ action->name = g_strdup (action_name);
+ if (parameter_type)
+ action->parameter_type = g_variant_type_new (parameter_type);
+ else
+ action->parameter_type = NULL;
+ action->activate = activate;
+
+ gtk_widget_class_add_action (widget_class, action);
+}
+
+static const GVariantType *
+determine_type (GParamSpec *pspec)
+{
+ if (G_TYPE_IS_ENUM (pspec->value_type))
+ return G_VARIANT_TYPE_STRING;
+
+ switch (pspec->value_type)
+ {
+ case G_TYPE_BOOLEAN:
+ return G_VARIANT_TYPE_BOOLEAN;
+
+ case G_TYPE_INT:
+ return G_VARIANT_TYPE_INT32;
+
+ case G_TYPE_UINT:
+ return G_VARIANT_TYPE_UINT32;
+
+ case G_TYPE_DOUBLE:
+ case G_TYPE_FLOAT:
+ return G_VARIANT_TYPE_DOUBLE;
+
+ case G_TYPE_STRING:
+ return G_VARIANT_TYPE_STRING;
+
+ default:
+ g_critical ("Unable to use gtk_widget_class_install_property_action with property '%s::%s' of type
'%s'",
+ g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->value_type));
+ return NULL;
+ }
}
-/*
- * gtk_widget_class_install_stateful_action:
- * @widget_class: a #GtkWidgetClass
- * @action_name: a prefixed action name, such as "clipboard.paste"
- * @parameter_type: (allow-none): the parameter type, or %NULL
- * @activate: callback to use when the action is activated
- * @state_type: (allow-none): the state type, or %NULL
- * @set_state: (allow-none): callback to use when the action state
- is set, or %NULL for stateless actions
- * @get_state: (allow-none): callback to use when the action state
- is queried, or %NULL for stateless actions
- *
- * This should be called at class initialization time to specify
- * actions to be added for all instances of this class.
- *
- * Actions installed in this way can be simple or stateful.
- * See the #GAction documentation for more information.
- */
void
-gtk_widget_class_install_stateful_action (GtkWidgetClass *widget_class,
- const char *action_name,
- const char *parameter_type,
- GtkWidgetActionActivateFunc activate,
- const char *state_type,
- GtkWidgetActionSetStateFunc set_state,
- GtkWidgetActionGetStateFunc get_state)
+gtk_widget_class_install_property_action (GtkWidgetClass *widget_class,
+ const char *action_name,
+ const char *property_name)
{
- GtkWidgetClassPrivate *priv = widget_class->priv;
+ GParamSpec *pspec;
GtkWidgetAction *action;
g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
- if (priv->actions == NULL)
- priv->actions = g_ptr_array_new ();
- else if (GTK_IS_WIDGET_CLASS (&widget_class->parent_class))
- {
- GtkWidgetClass *parent_class = GTK_WIDGET_CLASS (&widget_class->parent_class);
- GtkWidgetClassPrivate *parent_priv = parent_class->priv;
- GPtrArray *parent_actions = parent_priv->actions;
+ pspec = g_object_class_find_property (G_OBJECT_CLASS (widget_class), property_name);
- if (priv->actions == parent_actions)
- {
- int i;
+ if (pspec == NULL)
+ {
+ g_critical ("Attempted to use non-existent property '%s::%s' for
dgtk_widget_class_install_property_action",
+ g_type_name (G_TYPE_FROM_CLASS (widget_class)), property_name);
+ return;
+ }
- priv->actions = g_ptr_array_new ();
- for (i = 0; i < parent_actions->len; i++)
- g_ptr_array_add (priv->actions, g_ptr_array_index (parent_actions, i));
- }
+ if (~pspec->flags & G_PARAM_READABLE || ~pspec->flags & G_PARAM_WRITABLE || pspec->flags &
G_PARAM_CONSTRUCT_ONLY)
+ {
+ g_critical ("Property '%s::%s' used with gtk_widget_class_install_property_action must be readable,
writable, and not construct-only",
+ g_type_name (G_TYPE_FROM_CLASS (widget_class)), property_name);
+ return;
}
action = g_new0 (GtkWidgetAction, 1);
action->owner = G_TYPE_FROM_CLASS (widget_class);
action->name = g_strdup (action_name);
- action->parameter_type = parameter_type ? g_variant_type_new (parameter_type) : NULL;
- action->activate = activate;
- action->state_type = state_type ? g_variant_type_new (state_type) : NULL;
- action->set_state = set_state;
- action->get_state = get_state;
-
- GTK_NOTE(ACTIONS,
- g_message ("%sClass: Adding %s action\n",
- g_type_name (G_TYPE_FROM_CLASS (widget_class)),
- action_name));
+ action->pspec = pspec;
+ action->state_type = determine_type (action->pspec);
+ if (action->pspec->value_type == G_TYPE_BOOLEAN)
+ action->parameter_type = NULL;
+ else
+ action->parameter_type = action->state_type;
+ action->activate = NULL;
- g_ptr_array_add (priv->actions, action);
+ gtk_widget_class_add_action (widget_class, action);
}
/**
@@ -13545,29 +13589,6 @@ gtk_widget_action_enabled_changed (GtkWidget *widget,
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
}
-/**
- * gtk_widget_action_state_changed:
- * @widget: a #GtkWidget
- * @action_name: action name, such as "clipboard.paste"
- * @state: the new state
- *
- * Notify when an action installed with
- * gtk_widget_class_install_stateful_action() changes
- * its state.
- */
-void
-gtk_widget_action_state_changed (GtkWidget *widget,
- const char *action_name,
- GVariant *state)
-{
- GtkActionMuxer *muxer;
-
- g_return_if_fail (GTK_IS_WIDGET (widget));
-
- muxer = _gtk_widget_get_action_muxer (widget, TRUE);
- gtk_action_muxer_action_state_changed (muxer, action_name, state);
-}
-
/**
* gtk_widget_class_query_action:
* @widget_class: a #GtkWidgetClass
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index c1a0482278..a9b1434f27 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -1038,38 +1038,6 @@ typedef void (* GtkWidgetActionActivateFunc) (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
-/**
- * GtkWidgetActionGetStateFunc:
- * @widget: the widget to which the action belongs
- * @action_name: the action name
- *
- * The type of the callback functions used to query the state
- * of stateful actions installed with gtk_widget_class_install_action().
- *
- * See the #GAction documentation for more details about the
- * meaning of these properties.
- */
-typedef GVariant * (* GtkWidgetActionGetStateFunc) (GtkWidget *widget,
- const char *action_name);
-
-/**
- * GtkWidgetActionSetStateFunc:
- * @widget: the widget to which the action belongs
- * @action_name: the action name
- * @state: the new state
- *
- * The type of the callback functions used to change the
- * state of actions installed with gtk_widget_class_install_action().
- *
- * The @state must match the @state_type of the action.
- *
- * This callback is used when the action state is
- * changed via the #GActionGroup API.
- */
-typedef void (*GtkWidgetActionSetStateFunc) (GtkWidget *widget,
- const char *action_name,
- GVariant *state);
-
GDK_AVAILABLE_IN_ALL
void gtk_widget_class_install_action (GtkWidgetClass *widget_class,
const char *action_name,
@@ -1077,13 +1045,9 @@ void gtk_widget_class_install_action (GtkWidgetClass
GtkWidgetActionActivateFunc activate);
GDK_AVAILABLE_IN_ALL
-void gtk_widget_class_install_stateful_action (GtkWidgetClass *widget_class,
- const char *action_name,
- const char
*parameter_type,
- GtkWidgetActionActivateFunc activate,
- const char *state_type,
- GtkWidgetActionSetStateFunc set_state,
- GtkWidgetActionGetStateFunc get_state);
+void gtk_widget_class_install_property_action (GtkWidgetClass *widget_class,
+ const char *action_name,
+ const char *property_name);
GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_class_query_action (GtkWidgetClass *widget_class,
@@ -1097,10 +1061,6 @@ GDK_AVAILABLE_IN_ALL
void gtk_widget_action_enabled_changed (GtkWidget *widget,
const char *action_name,
gboolean enabled);
-GDK_AVAILABLE_IN_ALL
-void gtk_widget_action_state_changed (GtkWidget *widget,
- const char *action_name,
- GVariant *state);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)
diff --git a/gtk/meson.build b/gtk/meson.build
index c5bd9b154f..0b271b6f50 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -17,6 +17,7 @@ gtk_private_sources = files([
'fallback-c89.c',
'fnmatch.c',
'tools/gdkpixbufutils.c',
+ 'gsettings-mapping.c',
'gtkactionhelper.c',
'gtkactionmuxer.c',
'gtkactionobservable.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]