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.
This commit is contained in:
Matthias Clasen 2019-06-22 20:18:05 +00:00
parent 7e73da5f73
commit d1f4068b94
9 changed files with 900 additions and 186 deletions

View File

@ -4630,13 +4630,10 @@ gtk_widget_insert_action_group
gtk_widget_activate_action gtk_widget_activate_action
gtk_widget_activate_default gtk_widget_activate_default
GtkWidgetActionActivateFunc GtkWidgetActionActivateFunc
GtkWidgetActionSetStateFunc
GtkWidgetActionGetStateFunc
gtk_widget_class_install_action gtk_widget_class_install_action
gtk_widget_class_install_stateful_action gtk_widget_class_install_property_action
gtk_widget_class_query_action gtk_widget_class_query_action
gtk_widget_action_enabled_changed gtk_widget_action_enabled_changed
gtk_widget_action_state_changed
<SUBSECTION Standard> <SUBSECTION Standard>
GTK_WIDGET GTK_WIDGET

592
gtk/gsettings-mapping.c Normal file
View File

@ -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;
}

34
gtk/gsettings-mapping.h Normal file
View File

@ -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__ */

View File

@ -26,6 +26,7 @@
#include "gtkintl.h" #include "gtkintl.h"
#include "gtkmarshalers.h" #include "gtkmarshalers.h"
#include "gtkwidget.h" #include "gtkwidget.h"
#include "gsettings-mapping.h"
#include <string.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); 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 static gboolean
gtk_action_muxer_query_action (GActionGroup *action_group, gtk_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name, const gchar *action_name,
@ -454,16 +594,12 @@ gtk_action_muxer_query_action (GActionGroup *action_group,
if (state) if (state)
*state = NULL; *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) if (state)
*state = g_variant_ref (s); *state = prop_action_get_state (muxer->widget, action);
if (state_hint)
g_variant_unref (s); *state_hint = prop_action_get_state_hint (muxer->widget, action);
} }
return TRUE; return TRUE;
@ -503,7 +639,10 @@ gtk_action_muxer_activate_action (GActionGroup *action_group,
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i); GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0) 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; return;
} }
@ -536,8 +675,8 @@ gtk_action_muxer_change_action_state (GActionGroup *action_group,
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i); GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0) if (strcmp (action->name, action_name) == 0)
{ {
if (action->set_state) if (action->pspec)
action->set_state (muxer->widget, action->name, state); prop_action_set_state (muxer->widget, action, state);
return; return;
} }
@ -668,6 +807,8 @@ gtk_action_muxer_dispose (GObject *object)
{ {
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object); GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
prop_actions_disconnect (muxer);
if (muxer->parent) if (muxer->parent)
{ {
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer); 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); ->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 static void
gtk_action_muxer_get_property (GObject *object, gtk_action_muxer_get_property (GObject *object,
guint property_id, guint property_id,
@ -775,6 +926,7 @@ gtk_action_muxer_class_init (GObjectClass *class)
{ {
class->get_property = gtk_action_muxer_get_property; class->get_property = gtk_action_muxer_get_property;
class->set_property = gtk_action_muxer_set_property; class->set_property = gtk_action_muxer_set_property;
class->constructed = gtk_action_muxer_constructed;
class->finalize = gtk_action_muxer_finalize; class->finalize = gtk_action_muxer_finalize;
class->dispose = gtk_action_muxer_dispose; class->dispose = gtk_action_muxer_dispose;

View File

@ -33,14 +33,13 @@ G_BEGIN_DECLS
typedef struct { typedef struct {
char *name; char *name;
GType owner; GType owner;
GVariantType *parameter_type;
GVariantType *state_type;
const GVariantType *parameter_type;
GtkWidgetActionActivateFunc activate; GtkWidgetActionActivateFunc activate;
GtkWidgetActionSetStateFunc set_state;
GtkWidgetActionGetStateFunc get_state; const GVariantType *state_type;
GParamSpec *pspec;
} GtkWidgetAction; } GtkWidgetAction;
typedef struct _GtkActionMuxer GtkActionMuxer; typedef struct _GtkActionMuxer GtkActionMuxer;

View File

@ -563,15 +563,6 @@ static void gtk_text_activate_selection_select_all (GtkWidget *widget,
static void gtk_text_activate_misc_insert_emoji (GtkWidget *widget, static void gtk_text_activate_misc_insert_emoji (GtkWidget *widget,
const char *action_name, const char *action_name,
GVariant *parameter); 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 /* GtkTextContent implementation
*/ */
@ -1375,11 +1366,9 @@ gtk_text_class_init (GtkTextClass *class)
gtk_text_activate_selection_select_all); gtk_text_activate_selection_select_all);
gtk_widget_class_install_action (widget_class, "misc.insert-emoji", NULL, gtk_widget_class_install_action (widget_class, "misc.insert-emoji", NULL,
gtk_text_activate_misc_insert_emoji); gtk_text_activate_misc_insert_emoji);
gtk_widget_class_install_stateful_action (widget_class, "misc.toggle-visibility", NULL, gtk_widget_class_install_property_action (widget_class,
gtk_text_activate_misc_toggle_visibility, "misc.toggle-visibility",
"b", "visibility");
gtk_text_set_misc_toggle_visibility,
gtk_text_get_misc_toggle_visibility);
} }
static void static void
@ -5313,8 +5302,6 @@ gtk_text_set_visibility (GtkText *self,
gtk_text_recompute (self); gtk_text_recompute (self);
gtk_text_update_clipboard_actions (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); 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 static void
gtk_text_update_clipboard_actions (GtkText *self) gtk_text_update_clipboard_actions (GtkText *self)
{ {

View File

@ -13430,6 +13430,37 @@ gtk_widget_should_layout (GtkWidget *widget)
return TRUE; 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: * gtk_widget_class_install_action:
* @widget_class: a #GtkWidgetClass * @widget_class: a #GtkWidgetClass
@ -13450,76 +13481,89 @@ gtk_widget_class_install_action (GtkWidgetClass *widget_class,
const char *parameter_type, const char *parameter_type,
GtkWidgetActionActivateFunc activate) GtkWidgetActionActivateFunc activate)
{ {
gtk_widget_class_install_stateful_action (widget_class, action_name, GtkWidgetAction *action;
parameter_type, activate,
NULL, NULL, NULL); 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 *
* gtk_widget_class_install_stateful_action: determine_type (GParamSpec *pspec)
* @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)
{ {
GtkWidgetClassPrivate *priv = widget_class->priv; 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;
}
}
void
gtk_widget_class_install_property_action (GtkWidgetClass *widget_class,
const char *action_name,
const char *property_name)
{
GParamSpec *pspec;
GtkWidgetAction *action; GtkWidgetAction *action;
g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
if (priv->actions == NULL) pspec = g_object_class_find_property (G_OBJECT_CLASS (widget_class), property_name);
priv->actions = g_ptr_array_new ();
else if (GTK_IS_WIDGET_CLASS (&widget_class->parent_class)) if (pspec == NULL)
{ {
GtkWidgetClass *parent_class = GTK_WIDGET_CLASS (&widget_class->parent_class); g_critical ("Attempted to use non-existent property '%s::%s' for dgtk_widget_class_install_property_action",
GtkWidgetClassPrivate *parent_priv = parent_class->priv; g_type_name (G_TYPE_FROM_CLASS (widget_class)), property_name);
GPtrArray *parent_actions = parent_priv->actions; return;
}
if (priv->actions == parent_actions) if (~pspec->flags & G_PARAM_READABLE || ~pspec->flags & G_PARAM_WRITABLE || pspec->flags & G_PARAM_CONSTRUCT_ONLY)
{ {
int i; 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);
priv->actions = g_ptr_array_new (); return;
for (i = 0; i < parent_actions->len; i++)
g_ptr_array_add (priv->actions, g_ptr_array_index (parent_actions, i));
}
} }
action = g_new0 (GtkWidgetAction, 1); action = g_new0 (GtkWidgetAction, 1);
action->owner = G_TYPE_FROM_CLASS (widget_class); action->owner = G_TYPE_FROM_CLASS (widget_class);
action->name = g_strdup (action_name); action->name = g_strdup (action_name);
action->parameter_type = parameter_type ? g_variant_type_new (parameter_type) : NULL; action->pspec = pspec;
action->activate = activate; action->state_type = determine_type (action->pspec);
action->state_type = state_type ? g_variant_type_new (state_type) : NULL; if (action->pspec->value_type == G_TYPE_BOOLEAN)
action->set_state = set_state; action->parameter_type = NULL;
action->get_state = get_state; else
action->parameter_type = action->state_type;
action->activate = NULL;
GTK_NOTE(ACTIONS, gtk_widget_class_add_action (widget_class, action);
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);
} }
/** /**
@ -13545,29 +13589,6 @@ gtk_widget_action_enabled_changed (GtkWidget *widget,
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled); 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: * gtk_widget_class_query_action:
* @widget_class: a #GtkWidgetClass * @widget_class: a #GtkWidgetClass

View File

@ -1038,38 +1038,6 @@ typedef void (* GtkWidgetActionActivateFunc) (GtkWidget *widget,
const char *action_name, const char *action_name,
GVariant *parameter); 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 GDK_AVAILABLE_IN_ALL
void gtk_widget_class_install_action (GtkWidgetClass *widget_class, void gtk_widget_class_install_action (GtkWidgetClass *widget_class,
const char *action_name, const char *action_name,
@ -1077,13 +1045,9 @@ void gtk_widget_class_install_action (GtkWidgetClass
GtkWidgetActionActivateFunc activate); GtkWidgetActionActivateFunc activate);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_widget_class_install_stateful_action (GtkWidgetClass *widget_class, void gtk_widget_class_install_property_action (GtkWidgetClass *widget_class,
const char *action_name, const char *action_name,
const char *parameter_type, const char *property_name);
GtkWidgetActionActivateFunc activate,
const char *state_type,
GtkWidgetActionSetStateFunc set_state,
GtkWidgetActionGetStateFunc get_state);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_class_query_action (GtkWidgetClass *widget_class, 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, void gtk_widget_action_enabled_changed (GtkWidget *widget,
const char *action_name, const char *action_name,
gboolean enabled); 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) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)

View File

@ -17,6 +17,7 @@ gtk_private_sources = files([
'fallback-c89.c', 'fallback-c89.c',
'fnmatch.c', 'fnmatch.c',
'tools/gdkpixbufutils.c', 'tools/gdkpixbufutils.c',
'gsettings-mapping.c',
'gtkactionhelper.c', 'gtkactionhelper.c',
'gtkactionmuxer.c', 'gtkactionmuxer.c',
'gtkactionobservable.c', 'gtkactionobservable.c',