[libpanel] action-muxer: add support for class actions and property actions
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpanel] action-muxer: add support for class actions and property actions
- Date: Thu, 28 Jul 2022 00:49:07 +0000 (UTC)
commit 4072afce867687c14a632a4904c9dcfb9cd5118e
Author: Christian Hergert <chergert redhat com>
Date: Wed Jul 27 17:47:33 2022 -0700
action-muxer: add support for class actions and property actions
This gives us most of what we had from GtkWidgetClass in a convenient
action muxer we can control. We don't get the part of action muxer that
lets us observe, but this at least gets us something we can group/insert
into GTK elsewhere.
Beyond that, we can probably make this useful outside of just
widgets so that we can have it in libide as well on IdeObject. Therefore
I tried to avoid the GTK'isms on the public API itself, even if they
are type compatible.
src/gsettings-mapping.c | 592 +++++++++++++++++++++++++++++++++++++++
src/gsettings-mapping.h | 34 +++
src/meson.build | 1 +
src/panel-action-muxer-private.h | 40 ++-
src/panel-action-muxer.c | 274 +++++++++++++++++-
src/panel-frame.c | 8 +-
src/panel-widget-private.h | 7 +-
src/panel-widget.c | 319 +++++++++++++++++++--
src/panel-widget.h | 111 ++++----
9 files changed, 1300 insertions(+), 86 deletions(-)
---
diff --git a/src/gsettings-mapping.c b/src/gsettings-mapping.c
new file mode 100644
index 0000000..8e22e13
--- /dev/null
+++ b/src/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 ((int) 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 ((double) l);
+
+ return variant;
+}
+
+static GVariant *
+g_settings_set_mapping_float (const GValue *value,
+ const GVariantType *expected_type)
+{
+ GVariant *variant = NULL;
+ double 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 ((int) 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 ((double) 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 ((int) 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 ((double) 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;
+ double 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)
+{
+ char *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 char **) 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 char *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 char *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/src/gsettings-mapping.h b/src/gsettings-mapping.h
new file mode 100644
index 0000000..8a26684
--- /dev/null
+++ b/src/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/src/meson.build b/src/meson.build
index e37fd38..b600160 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -18,6 +18,7 @@ panel_version_h = configure_file(
configuration: version_data)
libpanel_private_sources = [
+ 'gsettings-mapping.c',
'panel-action-muxer.c',
'panel-binding-group.c',
'panel-dock-child.c',
diff --git a/src/panel-action-muxer-private.h b/src/panel-action-muxer-private.h
index e694756..9dc4a65 100644
--- a/src/panel-action-muxer-private.h
+++ b/src/panel-action-muxer-private.h
@@ -24,19 +24,41 @@
G_BEGIN_DECLS
+typedef void (*PanelActionActivateFunc) (gpointer instance,
+ const char *action_name,
+ GVariant *param);
+
+typedef struct _PanelAction
+{
+ const struct _PanelAction *next;
+ const char *name;
+ GType owner;
+ const GVariantType *parameter_type;
+ const GVariantType *state_type;
+ GParamSpec *pspec;
+ PanelActionActivateFunc activate;
+ guint position;
+} PanelAction;
+
#define PANEL_TYPE_ACTION_MUXER (panel_action_muxer_get_type())
G_DECLARE_FINAL_TYPE (PanelActionMuxer, panel_action_muxer, PANEL, ACTION_MUXER, GObject)
PanelActionMuxer *panel_action_muxer_new (void);
-void panel_action_muxer_insert_action_group (PanelActionMuxer *self,
- const char *prefix,
- GActionGroup *action_group);
-void panel_action_muxer_remove_action_group (PanelActionMuxer *self,
- const char *prefix);
-char **panel_action_muxer_list_groups (PanelActionMuxer *self);
-GActionGroup *panel_action_muxer_get_action_group (PanelActionMuxer *self,
- const char *prefix);
-void panel_action_muxer_clear (PanelActionMuxer *self);
+void panel_action_muxer_remove_all (PanelActionMuxer *self);
+void panel_action_muxer_insert_action_group (PanelActionMuxer *self,
+ const char *prefix,
+ GActionGroup *action_group);
+void panel_action_muxer_remove_action_group (PanelActionMuxer *self,
+ const char *prefix);
+char **panel_action_muxer_list_groups (PanelActionMuxer *self);
+GActionGroup *panel_action_muxer_get_action_group (PanelActionMuxer *self,
+ const char *prefix);
+void panel_action_muxer_set_enabled (PanelActionMuxer *self,
+ const PanelAction *action,
+ gboolean enabled);
+void panel_action_muxer_connect_actions (PanelActionMuxer *self,
+ gpointer instance,
+ const PanelAction *actions);
G_END_DECLS
diff --git a/src/panel-action-muxer.c b/src/panel-action-muxer.c
index 382e61f..1ac0d98 100644
--- a/src/panel-action-muxer.c
+++ b/src/panel-action-muxer.c
@@ -20,13 +20,21 @@
#include "config.h"
+#include <gtk/gtk.h>
+
+#include "gsettings-mapping.h"
#include "panel-action-muxer-private.h"
struct _PanelActionMuxer
{
- GObject parent_instance;
- GPtrArray *action_groups;
- guint n_recurse;
+ GObject parent_instance;
+ GPtrArray *action_groups;
+ const PanelAction *actions;
+ GtkBitset *actions_disabled;
+ GHashTable *pspec_name_to_action;
+ gpointer instance;
+ gulong instance_notify_handler;
+ guint n_recurse;
};
typedef struct
@@ -74,14 +82,43 @@ prefixed_action_group_ref (PrefixedActionGroup *pag)
return g_rc_box_acquire (pag);
}
+static GVariant *
+get_property_state (gpointer instance,
+ GParamSpec *pspec,
+ const GVariantType *state_type)
+{
+ GValue value = G_VALUE_INIT;
+ GVariant *ret;
+
+ g_assert (G_IS_OBJECT (instance));
+ g_assert (pspec != NULL);
+ g_assert (state_type != NULL);
+
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (instance, pspec->name, &value);
+ ret = g_settings_set_mapping (&value, state_type, NULL);
+ g_value_unset (&value);
+
+ return g_variant_ref_sink (ret);
+}
+
static void
panel_action_muxer_dispose (GObject *object)
{
PanelActionMuxer *self = (PanelActionMuxer *)object;
+ if (self->instance != NULL)
+ {
+ g_clear_signal_handler (&self->instance_notify_handler, self->instance);
+ g_clear_weak_pointer (&self->instance);
+ }
+
if (self->action_groups->len > 0)
g_ptr_array_remove_range (self->action_groups, 0, self->action_groups->len);
+ self->actions = NULL;
+ g_clear_pointer (&self->actions_disabled, gtk_bitset_unref);
+
G_OBJECT_CLASS (panel_action_muxer_parent_class)->finalize (object);
}
@@ -108,6 +145,7 @@ static void
panel_action_muxer_init (PanelActionMuxer *self)
{
self->action_groups = g_ptr_array_new_with_free_func ((GDestroyNotify)prefixed_action_group_drop);
+ self->actions_disabled = gtk_bitset_new_empty ();
}
PanelActionMuxer *
@@ -378,6 +416,12 @@ panel_action_muxer_has_action (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ return TRUE;
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -400,6 +444,12 @@ panel_action_muxer_list_actions (GActionGroup *group)
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
GArray *ar = g_array_new (TRUE, FALSE, sizeof (char *));
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ char *name = g_strdup (iter->name);
+ g_array_append_val (ar, name);
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -421,6 +471,12 @@ panel_action_muxer_get_action_enabled (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (action_name, iter->name) == 0)
+ return !gtk_bitset_contains (self->actions_disabled, iter->position);
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -443,6 +499,16 @@ panel_action_muxer_get_action_state (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ {
+ if (iter->pspec != NULL && self->instance != NULL)
+ return get_property_state (self->instance, iter->pspec, iter->state_type);
+ return NULL;
+ }
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -465,6 +531,38 @@ panel_action_muxer_get_action_state_hint (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ {
+ if (iter->pspec != NULL)
+ {
+ if (iter->pspec->value_type == G_TYPE_INT)
+ {
+ GParamSpecInt *pspec = (GParamSpecInt *)iter->pspec;
+ return g_variant_new ("(ii)", pspec->minimum, pspec->maximum);
+ }
+ else if (iter->pspec->value_type == G_TYPE_UINT)
+ {
+ GParamSpecUInt *pspec = (GParamSpecUInt *)iter->pspec;
+ return g_variant_new ("(uu)", pspec->minimum, pspec->maximum);
+ }
+ else if (iter->pspec->value_type == G_TYPE_FLOAT)
+ {
+ GParamSpecFloat *pspec = (GParamSpecFloat *)iter->pspec;
+ return g_variant_new ("(dd)", (double)pspec->minimum, (double)pspec->maximum);
+ }
+ else if (iter->pspec->value_type == G_TYPE_DOUBLE)
+ {
+ GParamSpecDouble *pspec = (GParamSpecDouble *)iter->pspec;
+ return g_variant_new ("(dd)", pspec->minimum, pspec->maximum);
+ }
+ }
+
+ return NULL;
+ }
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -488,6 +586,23 @@ panel_action_muxer_change_action_state (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ {
+ if (iter->pspec != NULL && self->instance != NULL)
+ {
+ GValue gvalue = G_VALUE_INIT;
+ g_value_init (&gvalue, iter->pspec->value_type);
+ g_settings_get_mapping (&gvalue, value, NULL);
+ g_object_set_property (self->instance, iter->pspec->name, &gvalue);
+ g_value_unset (&gvalue);
+ }
+
+ return;
+ }
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -511,6 +626,12 @@ panel_action_muxer_get_action_state_type (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ return iter->state_type;
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -534,6 +655,39 @@ panel_action_muxer_activate_action (GActionGroup *group,
{
PanelActionMuxer *self = PANEL_ACTION_MUXER (group);
+ for (const PanelAction *iter = self->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ {
+ if (iter->pspec != NULL)
+ {
+ if (iter->pspec->value_type == G_TYPE_BOOLEAN)
+ {
+ gboolean value;
+
+ g_return_if_fail (parameter == NULL);
+
+ g_object_get (self->instance, iter->pspec->name, &value, NULL);
+ value = !value;
+ g_object_set (self->instance, iter->pspec->name, value, NULL);
+ }
+ else
+ {
+ g_return_if_fail (parameter != NULL && g_variant_is_of_type (parameter, iter->state_type));
+
+ panel_action_muxer_change_action_state (group, action_name, parameter);
+ }
+
+ }
+ else
+ {
+ iter->activate (self->instance, iter->name, parameter);
+ }
+
+ return;
+ }
+ }
+
for (guint i = 0; i < self->action_groups->len; i++)
{
const PrefixedActionGroup *pag = g_ptr_array_index (self->action_groups, i);
@@ -588,7 +742,7 @@ action_group_iface_init (GActionGroupInterface *iface)
}
void
-panel_action_muxer_clear (PanelActionMuxer *self)
+panel_action_muxer_remove_all (PanelActionMuxer *self)
{
g_auto(GStrv) action_groups = NULL;
@@ -600,3 +754,115 @@ panel_action_muxer_clear (PanelActionMuxer *self)
panel_action_muxer_remove_action_group (self, action_groups[i]);
}
}
+
+void
+panel_action_muxer_set_enabled (PanelActionMuxer *self,
+ const PanelAction *action,
+ gboolean enabled)
+{
+ gboolean disabled = !enabled;
+
+ g_return_if_fail (PANEL_IS_ACTION_MUXER (self));
+ g_return_if_fail (action != NULL);
+
+ if (disabled != gtk_bitset_contains (self->actions_disabled, action->position))
+ {
+ if (disabled)
+ gtk_bitset_add (self->actions_disabled, action->position);
+ else
+ gtk_bitset_remove (self->actions_disabled, action->position);
+
+ g_action_group_action_enabled_changed (G_ACTION_GROUP (self), action->name, !disabled);
+ }
+}
+
+static void
+panel_action_muxer_property_action_notify_cb (PanelActionMuxer *self,
+ GParamSpec *pspec,
+ gpointer instance)
+{
+ g_autoptr(GVariant) state = NULL;
+ const PanelAction *action;
+
+ g_assert (PANEL_IS_ACTION_MUXER (self));
+ g_assert (pspec != NULL);
+ g_assert (G_IS_OBJECT (instance));
+
+ if (!(action = g_hash_table_lookup (self->pspec_name_to_action, pspec->name)))
+ return;
+
+ state = get_property_state (instance, action->pspec, action->state_type);
+
+ g_action_group_action_state_changed (G_ACTION_GROUP (self), action->name, state);
+}
+
+static void
+panel_action_muxer_add_property_action (PanelActionMuxer *self,
+ gpointer instance,
+ const PanelAction *action)
+{
+ g_assert (PANEL_IS_ACTION_MUXER (self));
+ g_assert (G_IS_OBJECT (instance));
+ g_assert (action != NULL);
+ g_assert (action->pspec != NULL);
+ g_assert (g_type_is_a (G_OBJECT_TYPE (instance), action->owner));
+
+ if (self->pspec_name_to_action == NULL)
+ self->pspec_name_to_action = g_hash_table_new (NULL, NULL);
+
+ g_hash_table_insert (self->pspec_name_to_action,
+ (gpointer)action->pspec->name,
+ (gpointer)action);
+
+ if (self->instance_notify_handler == 0)
+ self->instance_notify_handler =
+ g_signal_connect_object (instance,
+ "notify",
+ G_CALLBACK (panel_action_muxer_property_action_notify_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_action_group_action_added (G_ACTION_GROUP (self), action->name);
+}
+
+static void
+panel_action_muxer_add_action (PanelActionMuxer *self,
+ gpointer instance,
+ const PanelAction *action)
+{
+ g_assert (PANEL_IS_ACTION_MUXER (self));
+ g_assert (G_IS_OBJECT (instance));
+ g_assert (action != NULL);
+ g_assert (g_type_is_a (G_OBJECT_TYPE (instance), action->owner));
+
+ g_action_group_action_added (G_ACTION_GROUP (self), action->name);
+}
+
+void
+panel_action_muxer_connect_actions (PanelActionMuxer *self,
+ gpointer instance,
+ const PanelAction *actions)
+{
+ g_return_if_fail (PANEL_IS_ACTION_MUXER (self));
+ g_return_if_fail (G_IS_OBJECT (instance));
+ g_return_if_fail (self->instance == NULL);
+
+ if (actions == NULL)
+ return;
+
+ g_set_weak_pointer (&self->instance, instance);
+
+ self->actions = actions;
+
+ for (const PanelAction *iter = actions; iter; iter = iter->next)
+ {
+ g_assert (iter->next == NULL ||
+ iter->position == iter->next->position + 1);
+ g_assert (iter->pspec != NULL || iter->activate != NULL);
+
+ if (iter->pspec != NULL)
+ panel_action_muxer_add_property_action (self, instance, iter);
+ else
+ panel_action_muxer_add_action (self, instance, iter);
+ }
+}
diff --git a/src/panel-frame.c b/src/panel-frame.c
index dfc283d..6cec0b3 100644
--- a/src/panel-frame.c
+++ b/src/panel-frame.c
@@ -231,8 +231,8 @@ static void
panel_frame_update_actions (PanelFrame *self)
{
PanelFramePrivate *priv = panel_frame_get_instance_private (self);
+ PanelActionMuxer *action_group = NULL;
PanelWidget *visible_child;
- GActionGroup *action_group = NULL;
GtkWidget *grid;
g_assert (PANEL_IS_FRAME (self));
@@ -241,8 +241,10 @@ panel_frame_update_actions (PanelFrame *self)
visible_child = panel_frame_get_visible_child (self);
if (visible_child != NULL)
- action_group = _panel_widget_get_action_group (visible_child);
- gtk_widget_insert_action_group (GTK_WIDGET (self), "page", action_group);
+ action_group = _panel_widget_get_action_muxer (visible_child);
+ gtk_widget_insert_action_group (GTK_WIDGET (self),
+ "page",
+ G_ACTION_GROUP (action_group));
gtk_widget_action_set_enabled (GTK_WIDGET (self), "page.move-right", grid && visible_child);
gtk_widget_action_set_enabled (GTK_WIDGET (self), "page.move-left", grid && visible_child);
diff --git a/src/panel-widget-private.h b/src/panel-widget-private.h
index 4e58138..4541843 100644
--- a/src/panel-widget-private.h
+++ b/src/panel-widget-private.h
@@ -20,12 +20,13 @@
#pragma once
+#include "panel-action-muxer-private.h"
#include "panel-widget.h"
G_BEGIN_DECLS
-gboolean _panel_widget_can_save (PanelWidget *self);
-void _panel_widget_emit_presented (PanelWidget *self);
-GActionGroup *_panel_widget_get_action_group (PanelWidget *self);
+gboolean _panel_widget_can_save (PanelWidget *self);
+void _panel_widget_emit_presented (PanelWidget *self);
+PanelActionMuxer *_panel_widget_get_action_muxer (PanelWidget *self);
G_END_DECLS
diff --git a/src/panel-widget.c b/src/panel-widget.c
index 2078ae3..b75618a 100644
--- a/src/panel-widget.c
+++ b/src/panel-widget.c
@@ -18,6 +18,30 @@
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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 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/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
#include "config.h"
#include "panel-action-muxer-private.h"
@@ -49,11 +73,15 @@ typedef struct
guint needs_attention : 1;
} PanelWidgetPrivate;
-static void buildable_iface_init (GtkBuildableIface *iface);
+typedef struct
+{
+ const PanelAction *actions;
+} PanelWidgetClassPrivate;
-G_DEFINE_TYPE_WITH_CODE (PanelWidget, panel_widget, GTK_TYPE_WIDGET,
- G_ADD_PRIVATE (PanelWidget)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
+static void panel_widget_class_init_buildable (GtkBuildableIface *iface);
+static void panel_widget_class_init (PanelWidgetClass *klass);
+static void panel_widget_init (GTypeInstance *instance,
+ gpointer g_class);
enum {
PROP_0,
@@ -80,7 +108,65 @@ enum {
};
static GParamSpec *properties [N_PROPS];
-static guint signals [N_SIGNALS];
+static guint signals [N_SIGNALS];
+static int PanelWidget_private_offset;
+static gpointer panel_widget_parent_class;
+
+static inline gpointer
+panel_widget_get_instance_private (PanelWidget *self)
+{
+ return (G_STRUCT_MEMBER_P (self, PanelWidget_private_offset));
+}
+
+static inline gpointer
+panel_widget_class_get_private (PanelWidgetClass *widget_class)
+{
+ return G_TYPE_CLASS_GET_PRIVATE (widget_class, PANEL_TYPE_WIDGET, PanelWidgetClassPrivate);
+}
+
+GType
+panel_widget_get_type (void)
+{
+ static GType widget_type = 0;
+
+ if G_UNLIKELY (widget_type == 0)
+ {
+ const GTypeInfo widget_info =
+ {
+ sizeof (PanelWidgetClass),
+ NULL,
+ NULL,
+ (GClassInitFunc)panel_widget_class_init,
+ NULL,
+ NULL,
+ sizeof (PanelWidget),
+ 0,
+ panel_widget_init,
+ NULL,
+ };
+
+ const GInterfaceInfo buildable_info =
+ {
+ (GInterfaceInitFunc)panel_widget_class_init_buildable,
+ (GInterfaceFinalizeFunc)NULL,
+ NULL /* interface data */
+ };
+
+ widget_type = g_type_register_static (GTK_TYPE_WIDGET,
+ g_intern_static_string ("PanelWidget"),
+ &widget_info,
+ 0);
+ g_type_add_class_private (widget_type,
+ sizeof (PanelWidgetClassPrivate));
+ PanelWidget_private_offset = g_type_add_instance_private (widget_type,
+ sizeof (PanelWidgetPrivate));
+ g_type_add_interface_static (widget_type,
+ GTK_TYPE_BUILDABLE,
+ &buildable_info);
+ }
+
+ return widget_type;
+}
static void
panel_widget_update_actions (PanelWidget *self)
@@ -89,9 +175,9 @@ panel_widget_update_actions (PanelWidget *self)
g_assert (PANEL_IS_WIDGET (self));
- gtk_widget_action_set_enabled (GTK_WIDGET (self),
- "page.maximize",
- !priv->maximized && panel_widget_get_can_maximize (self));
+ panel_widget_action_set_enabled (self,
+ "page.maximize",
+ !priv->maximized && panel_widget_get_can_maximize (self));
}
static void
@@ -150,6 +236,21 @@ panel_widget_size_allocate (GtkWidget *widget,
gtk_widget_allocate (priv->child, width, height, baseline, NULL);
}
+static void
+panel_widget_constructed (GObject *object)
+{
+ PanelWidget *self = PANEL_WIDGET (object);
+ PanelWidgetClass *widget_class = PANEL_WIDGET_GET_CLASS (self);
+ PanelWidgetClassPrivate *class_priv = panel_widget_class_get_private (widget_class);
+ PanelActionMuxer *muxer;
+
+ G_OBJECT_CLASS (panel_widget_parent_class)->constructed (object);
+
+ muxer = PANEL_ACTION_MUXER (_panel_widget_get_action_muxer (self));
+
+ panel_action_muxer_connect_actions (muxer, self, class_priv->actions);
+}
+
static void
panel_widget_dispose (GObject *object)
{
@@ -158,7 +259,7 @@ panel_widget_dispose (GObject *object)
if (priv->action_muxer != NULL)
{
- panel_action_muxer_clear (priv->action_muxer);
+ panel_action_muxer_remove_all (priv->action_muxer);
g_clear_object (&priv->action_muxer);
}
@@ -300,6 +401,10 @@ panel_widget_class_init (PanelWidgetClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ g_type_class_adjust_private_offset (klass, &PanelWidget_private_offset);
+ panel_widget_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->constructed = panel_widget_constructed;
object_class->dispose = panel_widget_dispose;
object_class->get_property = panel_widget_get_property;
object_class->set_property = panel_widget_set_property;
@@ -461,7 +566,7 @@ panel_widget_class_init (PanelWidgetClass *klass)
gtk_widget_class_set_css_name (widget_class, "panelwidget");
- gtk_widget_class_install_action (widget_class, "page.maximize", NULL, panel_widget_maximize_action);
+ panel_widget_class_install_action (klass, "page.maximize", NULL, panel_widget_maximize_action);
/* Ensure we have quarks for known types */
g_quark_from_static_string (PANEL_WIDGET_KIND_ANY);
@@ -471,8 +576,10 @@ panel_widget_class_init (PanelWidgetClass *klass)
}
static void
-panel_widget_init (PanelWidget *self)
+panel_widget_init (GTypeInstance *instance,
+ gpointer g_class)
{
+ PanelWidget *self = PANEL_WIDGET (instance);
PanelWidgetPrivate *priv = panel_widget_get_instance_private (self);
panel_widget_update_actions (self);
@@ -1064,7 +1171,7 @@ panel_widget_add_child (GtkBuildable *buildable,
}
static void
-buildable_iface_init (GtkBuildableIface *iface)
+panel_widget_class_init_buildable (GtkBuildableIface *iface)
{
iface->add_child = panel_widget_add_child;
}
@@ -1146,15 +1253,15 @@ _panel_widget_emit_presented (PanelWidget *self)
g_signal_emit (self, signals [PRESENTED], 0);
}
-GActionGroup *
-_panel_widget_get_action_group (PanelWidget *self)
+PanelActionMuxer *
+_panel_widget_get_action_muxer (PanelWidget *self)
{
PanelWidgetPrivate *priv = panel_widget_get_instance_private (self);
if (priv->action_muxer == NULL)
priv->action_muxer = panel_action_muxer_new ();
- return G_ACTION_GROUP (priv->action_muxer);
+ return priv->action_muxer;
}
void
@@ -1162,12 +1269,188 @@ panel_widget_insert_action_group (PanelWidget *self,
const char *prefix,
GActionGroup *group)
{
- GActionGroup *muxer;
+ PanelActionMuxer *muxer;
g_return_if_fail (PANEL_IS_WIDGET (self));
g_return_if_fail (prefix != NULL);
- muxer = _panel_widget_get_action_group (self);
+ if ((muxer = _panel_widget_get_action_muxer (self)))
+ panel_action_muxer_insert_action_group (muxer, prefix, group);
+}
+
+static void
+panel_widget_class_add_action (PanelWidgetClass *widget_class,
+ PanelAction *action)
+{
+ PanelWidgetClassPrivate *class_priv = panel_widget_class_get_private (widget_class);
+
+ g_assert (PANEL_IS_WIDGET_CLASS (widget_class));
+ g_assert (action != NULL);
+ g_assert (action->next == NULL);
+ g_assert (action->position == 0);
+
+ /* Precalculate action "position". To be stable this is the
+ * number of items from the end.
+ */
+ for (const PanelAction *iter = class_priv->actions;
+ iter != NULL;
+ iter = iter->next)
+ action->position++;
+
+ action->next = class_priv->actions;
+ class_priv->actions = action;
+}
+
+/**
+ * panel_widget_class_install_action:
+ * @widget_class: a `PanelWidgetClass`
+ * @action_name: a prefixed action name, such as "clipboard.paste"
+ * @parameter_type: (nullable): the parameter type
+ * @activate: (scope notified): callback to use when the action is activated
+ *
+ * This should be called at class initialization time to specify
+ * actions to be added for all instances of this class.
+ *
+ * Actions installed by this function are stateless. The only state
+ * they have is whether they are enabled or not.
+ */
+void
+panel_widget_class_install_action (PanelWidgetClass *widget_class,
+ const char *action_name,
+ const char *parameter_type,
+ GtkWidgetActionActivateFunc activate)
+{
+ PanelAction *action;
+
+ g_return_if_fail (PANEL_IS_WIDGET_CLASS (widget_class));
+ g_return_if_fail (action_name != NULL);
+ g_return_if_fail (activate != NULL);
- panel_action_muxer_insert_action_group (PANEL_ACTION_MUXER (muxer), prefix, group);
+ action = g_new0 (PanelAction, 1);
+ action->owner = G_TYPE_FROM_CLASS (widget_class);
+ action->name = g_intern_string (action_name);
+ if (parameter_type != NULL)
+ action->parameter_type = g_variant_type_new (parameter_type);
+ action->activate = (PanelActionActivateFunc)activate;
+
+ panel_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 panel_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;
+ }
+}
+
+/**
+ * panel_widget_class_install_property_action:
+ * @widget_class: a `GtkWidgetClass`
+ * @action_name: name of the action
+ * @property_name: name of the property in instances of @widget_class
+ * or any parent class.
+ *
+ * Installs an action called @action_name on @widget_class and
+ * binds its state to the value of the @property_name property.
+ *
+ * This function will perform a few santity checks on the property selected
+ * via @property_name. Namely, the property must exist, must be readable,
+ * writable and must not be construct-only. There are also restrictions
+ * on the type of the given property, it must be boolean, int, unsigned int,
+ * double or string. If any of these conditions are not met, a critical
+ * warning will be printed and no action will be added.
+ *
+ * The state type of the action matches the property type.
+ *
+ * If the property is boolean, the action will have no parameter and
+ * toggle the property value. Otherwise, the action will have a parameter
+ * of the same type as the property.
+ */
+void
+panel_widget_class_install_property_action (PanelWidgetClass *widget_class,
+ const char *action_name,
+ const char *property_name)
+{
+ const GVariantType *state_type;
+ PanelAction *action;
+ GParamSpec *pspec;
+
+ g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
+
+ if (!(pspec = g_object_class_find_property (G_OBJECT_CLASS (widget_class), property_name)))
+ {
+ g_critical ("Attempted to use non-existent property '%s:%s' for
panel_widget_class_install_property_action",
+ G_OBJECT_CLASS_NAME (widget_class), property_name);
+ return;
+ }
+
+ if (~pspec->flags & G_PARAM_READABLE || ~pspec->flags & G_PARAM_WRITABLE || pspec->flags &
G_PARAM_CONSTRUCT_ONLY)
+ {
+ g_critical ("Property '%s:%s' used with panel_widget_class_install_property_action must be readable,
writable, and not construct-only",
+ G_OBJECT_CLASS_NAME (widget_class), property_name);
+ return;
+ }
+
+ state_type = determine_type (pspec);
+
+ if (!state_type)
+ return;
+
+ action = g_new0 (PanelAction, 1);
+ action->owner = G_TYPE_FROM_CLASS (widget_class);
+ action->name = g_intern_string (action_name);
+ action->pspec = pspec;
+ action->state_type = state_type;
+ if (action->pspec->value_type != G_TYPE_BOOLEAN)
+ action->parameter_type = action->state_type;
+
+ panel_widget_class_add_action (widget_class, action);
+}
+
+void
+panel_widget_action_set_enabled (PanelWidget *self,
+ const char *action_name,
+ gboolean enabled)
+{
+ PanelWidgetClassPrivate *class_priv;
+ PanelActionMuxer *muxer;
+
+ g_return_if_fail (PANEL_IS_WIDGET (self));
+ g_return_if_fail (action_name != NULL);
+
+ class_priv = panel_widget_class_get_private (PANEL_WIDGET_GET_CLASS (self));
+ muxer = _panel_widget_get_action_muxer (self);
+
+ for (const PanelAction *iter = class_priv->actions; iter; iter = iter->next)
+ {
+ if (g_strcmp0 (iter->name, action_name) == 0)
+ {
+ panel_action_muxer_set_enabled (muxer, iter, enabled);
+ break;
+ }
+ }
}
diff --git a/src/panel-widget.h b/src/panel-widget.h
index f161a2b..38c6590 100644
--- a/src/panel-widget.h
+++ b/src/panel-widget.h
@@ -34,10 +34,10 @@ G_DECLARE_DERIVABLE_TYPE (PanelWidget, panel_widget, PANEL, WIDGET, GtkWidget)
struct _PanelWidgetClass
{
- GtkWidgetClass parent_instance;
+ GtkWidgetClass parent_instance;
- GtkWidget *(*get_default_focus) (PanelWidget *self);
- void (*presented) (PanelWidget *self);
+ GtkWidget *(*get_default_focus) (PanelWidget *self);
+ void (*presented) (PanelWidget *self);
/*< private >*/
gpointer _reserved[8];
@@ -49,83 +49,96 @@ struct _PanelWidgetClass
#define PANEL_WIDGET_KIND_UTILITY "utility"
PANEL_AVAILABLE_IN_ALL
-GtkWidget *panel_widget_new (void);
+GtkWidget *panel_widget_new (void);
PANEL_AVAILABLE_IN_ALL
-GtkWidget *panel_widget_get_child (PanelWidget *self);
+GtkWidget *panel_widget_get_child (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_child (PanelWidget *self,
- GtkWidget *child);
+void panel_widget_set_child (PanelWidget *self,
+ GtkWidget *child);
PANEL_AVAILABLE_IN_ALL
-const char *panel_widget_get_title (PanelWidget *self);
+const char *panel_widget_get_title (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_title (PanelWidget *self,
- const char *title);
+void panel_widget_set_title (PanelWidget *self,
+ const char *title);
PANEL_AVAILABLE_IN_ALL
-GIcon *panel_widget_get_icon (PanelWidget *self);
+GIcon *panel_widget_get_icon (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_icon (PanelWidget *self,
- GIcon *icon);
+void panel_widget_set_icon (PanelWidget *self,
+ GIcon *icon);
PANEL_AVAILABLE_IN_ALL
-const char *panel_widget_get_icon_name (PanelWidget *self);
+const char *panel_widget_get_icon_name (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_icon_name (PanelWidget *self,
- const char *icon_name);
+void panel_widget_set_icon_name (PanelWidget *self,
+ const char *icon_name);
PANEL_AVAILABLE_IN_ALL
-gboolean panel_widget_get_reorderable (PanelWidget *self);
+gboolean panel_widget_get_reorderable (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_reorderable (PanelWidget *self,
- gboolean reorderable);
+void panel_widget_set_reorderable (PanelWidget *self,
+ gboolean reorderable);
PANEL_AVAILABLE_IN_ALL
-gboolean panel_widget_get_can_maximize (PanelWidget *self);
+gboolean panel_widget_get_can_maximize (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_can_maximize (PanelWidget *self,
- gboolean can_maximize);
+void panel_widget_set_can_maximize (PanelWidget *self,
+ gboolean can_maximize);
PANEL_AVAILABLE_IN_ALL
-gboolean panel_widget_get_modified (PanelWidget *self);
+gboolean panel_widget_get_modified (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_modified (PanelWidget *self,
- gboolean modified);
+void panel_widget_set_modified (PanelWidget *self,
+ gboolean modified);
PANEL_AVAILABLE_IN_ALL
-gboolean panel_widget_get_needs_attention (PanelWidget *self);
+gboolean panel_widget_get_needs_attention (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_needs_attention (PanelWidget *self,
- gboolean needs_attention);
+void panel_widget_set_needs_attention (PanelWidget *self,
+ gboolean needs_attention);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_maximize (PanelWidget *self);
+void panel_widget_maximize (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_unmaximize (PanelWidget *self);
+void panel_widget_unmaximize (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-const char *panel_widget_get_kind (PanelWidget *self);
+const char *panel_widget_get_kind (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_kind (PanelWidget *self,
- const char *kind);
+void panel_widget_set_kind (PanelWidget *self,
+ const char *kind);
PANEL_AVAILABLE_IN_ALL
-gboolean panel_widget_get_busy (PanelWidget *self);
+gboolean panel_widget_get_busy (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_mark_busy (PanelWidget *self);
+void panel_widget_mark_busy (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_unmark_busy (PanelWidget *self);
+void panel_widget_unmark_busy (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-GMenuModel *panel_widget_get_menu_model (PanelWidget *self);
+GMenuModel *panel_widget_get_menu_model (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_menu_model (PanelWidget *self,
- GMenuModel *menu_model);
+void panel_widget_set_menu_model (PanelWidget *self,
+ GMenuModel *menu_model);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_raise (PanelWidget *self);
+void panel_widget_raise (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-GtkWidget *panel_widget_get_default_focus (PanelWidget *self);
+GtkWidget *panel_widget_get_default_focus (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-gboolean panel_widget_focus_default (PanelWidget *self);
+gboolean panel_widget_focus_default (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-PanelSaveDelegate *panel_widget_get_save_delegate (PanelWidget *self);
+PanelSaveDelegate *panel_widget_get_save_delegate (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_set_save_delegate (PanelWidget *self,
- PanelSaveDelegate *save_delegate);
+void panel_widget_set_save_delegate (PanelWidget *self,
+ PanelSaveDelegate *save_delegate);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_close (PanelWidget *self);
+void panel_widget_close (PanelWidget *self);
PANEL_AVAILABLE_IN_ALL
-void panel_widget_insert_action_group (PanelWidget *self,
- const char *prefix,
- GActionGroup *group);
+void panel_widget_insert_action_group (PanelWidget *self,
+ const char *prefix,
+ GActionGroup *group);
+PANEL_AVAILABLE_IN_ALL
+void panel_widget_class_install_action (PanelWidgetClass *widget_class,
+ const char *action_name,
+ const char *parameter_type,
+ GtkWidgetActionActivateFunc activate);
+PANEL_AVAILABLE_IN_ALL
+void panel_widget_action_set_enabled (PanelWidget *widget,
+ const char *action_name,
+ gboolean enabled);
+PANEL_AVAILABLE_IN_ALL
+void panel_widget_class_install_property_action (PanelWidgetClass *widget_class,
+ const char *action_name,
+ const char *property_name);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]