Gobject tutorial 十三

参考:Gio.Action

GAction代表一个命名的action。那什么是action呢?我们运行一下gtk-3.14.15的gtk3-demo-application来使action变得可见。

是不是GAction所代表的action与鼠标点击动作之间可以划等号呢?暂时不清楚。那,什么是action呢,在这里我们可以理解为一个鼠标点击动作。

首先,我们看一下对于GAction的定义。

G_DEFINE_INTERFACE (GAction, g_action, G_TYPE_OBJECT)

GAction是一个Interface,那么Interface对应的数据结构又是什么呢。

struct _GActionInterface
{
  GTypeInterface g_iface;

  /* virtual functions */
  const gchar *        (* get_name)             (GAction  *action);
  const GVariantType * (* get_parameter_type)   (GAction  *action);
  const GVariantType * (* get_state_type)       (GAction  *action);
  GVariant *           (* get_state_hint)       (GAction  *action);

  gboolean             (* get_enabled)          (GAction  *action);
  GVariant *           (* get_state)            (GAction  *action);

  void                 (* change_state)         (GAction  *action,
                                                 GVariant *value);
  void                 (* activate)             (GAction  *action,
                                                 GVariant *parameter);
};

 在GLib中,Interface实际上是对一组函数的描述。详见GObject – 2.0: Type System Concepts

我们之前在Gobject tutorial 六-优快云博客中举例说明过interface的定义及用法。不像我们的例子,GAction在GLib中有具体的使用功能。由于Interface中函数的实现依赖于具体的类。在GLib中,对于GAction来说,这个类就是GSimpleAction。那么,在GSimpleAction中GAction是怎么实现的呢。

G_DEFINE_TYPE_WITH_CODE (GSimpleAction, g_simple_action, G_TYPE_OBJECT,
  G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_simple_action_iface_init))


void
g_simple_action_iface_init (GActionInterface *iface)
{
  iface->get_name = g_simple_action_get_name;
  iface->get_parameter_type = g_simple_action_get_parameter_type;
  iface->get_state_type = g_simple_action_get_state_type;
  iface->get_state_hint = g_simple_action_get_state_hint;
  iface->get_enabled = g_simple_action_get_enabled;
  iface->get_state = g_simple_action_get_state;
  iface->change_state = g_simple_action_change_state;
  iface->activate = g_simple_action_activate;
}

下面,我们以glib-2.78.2/gio/tests/actions.c为例,来了解一下GAction的用法。此篇,我们只了解GAction的用法这一个点,而不深究GAction与GObject的关系。由于GAction属于interface,而interface与具体类的关系,之前我们在Gobject tutorial 六-优快云博客 做过梳理。

现在,我们来看看actions.c的第一个测试函数test_basic,并在函数内注释。

static void
activate (GAction  *action,
          GVariant *parameter, //g_action_activate函数的第二个参数
          gpointer  user_data) //g_signal_connect函数的第三个参数
{
  Activation *activation = user_data;
  if (parameter)
    activation->params = g_variant_ref (parameter);
  else
    activation->params = NULL;
  activation->did_run = TRUE;
}

test_basic (void)
{
  Activation a = { 0, };
  GSimpleAction *action;
  gchar *name;
  GVariantType *parameter_type;
  gboolean enabled;
  GVariantType *state_type;
  GVariant *state;
//创建GSimpleAction实例
  action = g_simple_action_new ("foo", NULL);
//测试GSimpleAction实现的GAction的功能
  g_assert_true (g_action_get_enabled (G_ACTION (action)));//与下面的函数调用
//g_simple_action_set_enabled (action, FALSE);形成对比,此处的验证,说明当调用函数
//g_simple_action_new创建GSimpleAction时,
//与GSimpleAction相关的GAction处于enabled状态。
  g_assert_null (g_action_get_parameter_type (G_ACTION (action)));
  g_assert_null (g_action_get_state_type (G_ACTION (action)));
  g_assert_null (g_action_get_state_hint (G_ACTION (action)));
  g_assert_null (g_action_get_state (G_ACTION (action)));
  g_object_get (action,
                "name", &name,
                "parameter-type", &parameter_type,
                "enabled", &enabled,
                "state-type", &state_type,
                "state", &state,
                 NULL);
  g_assert_cmpstr (name, ==, "foo");
  g_assert_null (parameter_type);
  g_assert_true (enabled);
  g_assert_null (state_type);
  g_assert_null (state);
  g_free (name);

  g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
  g_assert_false (a.did_run);
//生成active信号
  g_action_activate (G_ACTION (action), NULL);
  g_assert_true (a.did_run);
  a.did_run = FALSE;
//设置action为不可用状态。
//详见https://docs.gtk.org/gio/method.SimpleAction.set_enabled.html
  g_simple_action_set_enabled (action, FALSE);
  g_action_activate (G_ACTION (action), NULL);
  g_assert_false (a.did_run);

.......
//与action = g_simple_action_new ("foo", NULL);对比,
//说明函数g_simple_action_new的第二个参数的用法。
  action = g_simple_action_new ("foo", G_VARIANT_TYPE_STRING);
  g_assert_true (g_action_get_enabled (G_ACTION (action)));
  g_assert_true (g_variant_type_equal (g_action_get_parameter_type (G_ACTION (action)), G_VARIANT_TYPE_STRING));
  g_assert_null (g_action_get_state_type (G_ACTION (action)));
  g_assert_null (g_action_get_state_hint (G_ACTION (action)));
  g_assert_null (g_action_get_state (G_ACTION (action)));

  g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
  g_assert_false (a.did_run);
//同样的,与g_simple_action_new ("foo", G_VARIANT_TYPE_STRING)一致,
//形成与g_action_activate (G_ACTION (action), NULL);的对比。
  g_action_activate (G_ACTION (action), g_variant_new_string ("Hello world"));
  g_assert_true (a.did_run);
  g_assert_cmpstr (g_variant_get_string (a.params, NULL), ==, "Hello world");
  g_variant_unref (a.params);
......
}

在官方文档Gio.Action 中,有这么一句话,An activation has a GVariant parameter (which may be NULL),至此,我们可以确定,这个GVariant就是函数g_action_activate的第二个参数。g_action_get_*这些函数最终都是使用GSimpleAction实现的GAction的函数。我们就以g_action_get_enabled来举例说明。

gboolean
g_action_get_enabled (GAction *action)
{
  g_return_val_if_fail (G_IS_ACTION (action), FALSE);

  return G_ACTION_GET_IFACE (action)
    ->get_enabled (action);
}

对于GSimpleAction来说,此处的get_enabled就是函数 g_simple_action_get_enabled。

接下来我们分析test_simple_group。

test_simple_group (void)
{
  GSimpleActionGroup *group;
  Activation a = { 0, };
  GSimpleAction *simple;
  GAction *action;
  gchar **actions;
  GVariant *state;

  simple = g_simple_action_new ("foo", NULL);
  g_signal_connect (simple, "activate", G_CALLBACK (activate), &a);
  g_assert_false (a.did_run);
  g_action_activate (G_ACTION (simple), NULL);
  g_assert_true (a.did_run);
  a.did_run = FALSE;
//新建一个GSimpleActionGroup
  group = g_simple_action_group_new ();
  g_simple_action_group_insert (group, G_ACTION (simple));
  g_object_unref (simple);

  g_assert_false (a.did_run);
  g_action_group_activate_action (G_ACTION_GROUP (group), "foo", NULL);
  g_assert_true (a.did_run);
//相对于test_basic,这里出现新的创建GSimpleAction的方式。
//定义参看https://docs.gtk.org/gio/ctor.SimpleAction.new_stateful.html
  simple = g_simple_action_new_stateful ("bar", G_VARIANT_TYPE_STRING, g_variant_new_string ("hihi"));
  g_simple_action_group_insert (group, G_ACTION (simple));
  g_object_unref (simple);

  g_assert_true (g_action_group_has_action (G_ACTION_GROUP (group), "foo"));
  g_assert_true (g_action_group_has_action (G_ACTION_GROUP (group), "bar"));
  g_assert_false (g_action_group_has_action (G_ACTION_GROUP (group), "baz"));
  actions = g_action_group_list_actions (G_ACTION_GROUP (group));
  g_assert_cmpint (g_strv_length (actions), ==, 2);
  g_assert_true (strv_set_equal ((const gchar * const *) actions, "foo", "bar", NULL));
  g_strfreev (actions);
  g_assert_true (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "foo"));
//与g_simple_action_new类似,g_simple_action_new_stateful也会使相关Action处于
//enabled状态。
  g_assert_true (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
  g_assert_null (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "foo"));
  g_assert_true (g_variant_type_equal (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
  g_assert_null (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "foo"));
  g_assert_true (g_variant_type_equal (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
  g_assert_null (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "foo"));
  g_assert_null (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "bar"));
  g_assert_null (g_action_group_get_action_state (G_ACTION_GROUP (group), "foo"));
  state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
  g_assert_true (g_variant_type_equal (g_variant_get_type (state), G_VARIANT_TYPE_STRING));
  g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
  g_variant_unref (state);

  g_action_group_change_action_state (G_ACTION_GROUP (group), "bar", g_variant_new_string ("boo"));
  state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
  g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "boo");
  g_variant_unref (state);

  action = g_simple_action_group_lookup (group, "bar");
  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
  g_assert_false (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));

  g_simple_action_group_remove (group, "bar");
  action = g_simple_action_group_lookup (group, "foo");
  g_assert_cmpstr (g_action_get_name (action), ==, "foo");
  action = g_simple_action_group_lookup (group, "bar");
  g_assert_null (action);
//之前以同样的名字新建过GSimpleAction,这里在测试什么呢?为了测试函数
//g_simple_action_group_insert的行为。
//详见https://docs.gtk.org/gio/method.SimpleActionGroup.insert.html
  simple = g_simple_action_new ("foo", NULL);
  g_simple_action_group_insert (group, G_ACTION (simple));
  g_object_unref (simple);

......
}

在test_simple_group函数中,出现了一个新概念GSimpleActionGroup,和一个新的创建GSimpleAction的函数g_simple_action_new_stateful。

我们先来看看GSimpleActionGroup。官方解释Gio.SimpleActionGroup,GSimpleActionGroup是一个用于存放GAction的哈希表,且GSimpleActionGroup实现了GActionGroup interface和GActionMap interface。下面我们看看这句话在GLib中是如何体现的。我们看看GSimpleActionGroup的定义。

/**
 * GSimpleActionGroup:
 *
 * The #GSimpleActionGroup structure contains private data and should only be accessed using the provided API.
 *
 * Since: 2.28
 */
struct _GSimpleActionGroup
{
  /*< private >*/
  GObject parent_instance;

  GSimpleActionGroupPrivate *priv;
};


/**
 * SECTION:gsimpleactiongroup
 * @title: GSimpleActionGroup
 * @short_description: A simple GActionGroup implementation
 * @include: gio/gio.h
 *
 * #GSimpleActionGroup is a hash table filled with #GAction objects,
 * implementing the #GActionGroup and #GActionMap interfaces.
 **/

struct _GSimpleActionGroupPrivate
{
  GHashTable *table;  /* string -> GAction */
};


G_DEFINE_TYPE_WITH_CODE (GSimpleActionGroup,
  g_simple_action_group, G_TYPE_OBJECT,
  G_ADD_PRIVATE (GSimpleActionGroup)
  G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
                         g_simple_action_group_iface_init);
  G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP,
                         g_simple_action_group_map_iface_init))

那么,在GSimpleActionGroup中,GActionGroup和GActionMap是如何被使用的呢?对此问题,我们先来看看这两个接口的定义,以及GSimpleActionGroup对这两个接口的实现。

struct _GActionGroupInterface
{
  GTypeInterface g_iface;

  /* virtual functions */
  gboolean              (* has_action)                 (GActionGroup  *action_group,
                                                        const gchar   *action_name);

  gchar **              (* list_actions)               (GActionGroup  *action_group);

  gboolean              (* get_action_enabled)         (GActionGroup  *action_group,
                                                        const gchar   *action_name);

  const GVariantType *  (* get_action_parameter_type)  (GActionGroup  *action_group,
                                                        const gchar   *action_name);

  const GVariantType *  (* get_action_state_type)      (GActionGroup  *action_group,
                                                        const gchar   *action_name);

  GVariant *            (* get_action_state_hint)      (GActionGroup  *action_group,
                                                        const gchar   *action_name);

  GVariant *            (* get_action_state)           (GActionGroup  *action_group,
                                                        const gchar   *action_name);

  void                  (* change_action_state)        (GActionGroup  *action_group,
                                                        const gchar   *action_name,
                                                        GVariant      *value);

  void                  (* activate_action)            (GActionGroup  *action_group,
                                                        const gchar   *action_name,
                                                        GVariant      *parameter);

  /* signals */
  void                  (* action_added)               (GActionGroup  *action_group,
                                                        const gchar   *action_name);
  void                  (* action_removed)             (GActionGroup  *action_group,
                                                        const gchar   *action_name);
  void                  (* action_enabled_changed)     (GActionGroup  *action_group,
                                                        const gchar   *action_name,
                                                        gboolean       enabled);
  void                  (* action_state_changed)       (GActionGroup   *action_group,
                                                        const gchar    *action_name,
                                                        GVariant       *state);

  /* more virtual functions */
  gboolean              (* query_action)               (GActionGroup        *action_group,
                                                        const gchar         *action_name,
                                                        gboolean            *enabled,
                                                        const GVariantType **parameter_type,
                                                        const GVariantType **state_type,
                                                        GVariant           **state_hint,
                                                        GVariant           **state);
};



struct _GActionMapInterface
{
  GTypeInterface g_iface;

  GAction * (* lookup_action) (GActionMap  *action_map,
                               const gchar *action_name);
  void      (* add_action)    (GActionMap  *action_map,
                               GAction     *action);
  void      (* remove_action) (GActionMap  *action_map,
                               const gchar *action_name);
};


static void
g_simple_action_group_iface_init (GActionGroupInterface *iface)
{
  iface->list_actions = g_simple_action_group_list_actions;
  iface->query_action = g_simple_action_group_query_action;
  iface->change_action_state = g_simple_action_group_change_state;
  iface->activate_action = g_simple_action_group_activate;
}

static void
g_simple_action_group_map_iface_init (GActionMapInterface *iface)
{
  iface->add_action = g_simple_action_group_add_action;
  iface->remove_action = g_simple_action_group_remove_action;
  iface->lookup_action = g_simple_action_group_lookup_action;
}

现在,我们举例来说明GSimpleAction是如何使用GActionGroup和GActionMap的。以test_simple_group中的g_action_group_get_action_enabled 和g_simple_action_group_lookup为例。

gboolean
g_action_group_get_action_enabled (GActionGroup *action_group,
                                   const gchar  *action_name)
{
  g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), FALSE);

  return G_ACTION_GROUP_GET_IFACE (action_group)
    ->get_action_enabled (action_group, action_name);
}


GAction *
g_simple_action_group_lookup (GSimpleActionGroup *simple,
                              const gchar        *action_name)
{
  g_return_val_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple), NULL);

  return g_action_map_lookup_action (G_ACTION_MAP (simple), action_name);
}

GAction *
g_action_map_lookup_action (GActionMap  *action_map,
                            const gchar *action_name)
{
  return G_ACTION_MAP_GET_IFACE (action_map)
    ->lookup_action (action_map, action_name);
}

待续。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值