[glib/application] add GAction class, tests



commit 2db4d38358e0568c0f45a7d143c4f6ad1d0d3f9f
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Aug 12 10:59:41 2010 -0400

    add GAction class, tests

 gio/Makefile.am       |    1 +
 gio/gaction.c         |  327 +++++++++++++++++++++++++++++++++++++++++++++++++
 gio/gaction.h         |  111 +++++++++++++++++
 gio/gio.h             |    1 +
 gio/giotypes.h        |    1 +
 gio/tests/.gitignore  |    1 +
 gio/tests/Makefile.am |    3 +
 gio/tests/actions.c   |   81 ++++++++++++
 8 files changed, 526 insertions(+), 0 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 46c6c8a..53a482b 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -260,6 +260,7 @@ SUBDIRS += tests
 
 libgio_2_0_la_SOURCES =		\
 	gappinfo.c 		\
+	gaction.c \
 	gapplicationimpl-dbus-interface.h \
 	gapplicationimpl-dbus-interface.c \
 	gapplicationcommandline.c\
diff --git a/gio/gaction.c b/gio/gaction.c
new file mode 100644
index 0000000..e0e8383
--- /dev/null
+++ b/gio/gaction.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ *
+ * This program 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 licence 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "gaction.h"
+
+G_DEFINE_TYPE (GAction, g_action, G_TYPE_OBJECT)
+
+struct _GActionPrivate
+{
+  gchar        *name;
+  GVariantType *parameter_type;
+  gboolean      enabled;
+
+  GVariantType *state_type;
+  GVariant     *state_range;
+  GVariant     *state;
+};
+
+enum
+{
+  PROP_NONE,
+  PROP_NAME,
+  PROP_PARAMETER_TYPE,
+  PROP_ENABLED,
+  PROP_STATE_TYPE,
+  PROP_STATE_RANGE,
+  PROP_STATE
+};
+
+enum
+{
+  SIGNAL_ACTIVATE,
+  NR_SIGNALS
+};
+
+static guint g_action_signals[NR_SIGNALS];
+
+static void
+g_action_set_property (GObject *object, guint prop_id,
+                       const GValue *value, GParamSpec *pspec)
+{
+  GAction *action = G_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_NAME:
+      g_assert (action->priv->name == NULL);
+      action->priv->name = g_value_dup_string (value);
+      break;
+
+    case PROP_PARAMETER_TYPE:
+      g_assert (action->priv->parameter_type == NULL);
+      action->priv->parameter_type = g_value_dup_boxed (value);
+      break;
+
+    case PROP_ENABLED:
+      g_action_set_enabled (action, g_value_get_boolean (value));
+      break;
+
+    case PROP_STATE_TYPE:
+      g_assert (action->priv->state_type == NULL);
+      action->priv->state_type = g_value_dup_boxed (value);
+      break;
+
+    case PROP_STATE_RANGE:
+      g_assert (action->priv->state_range == NULL);
+      action->priv->state_range = g_value_dup_variant (value);
+      break;
+
+    case PROP_STATE:
+      g_action_set_state (action, g_value_get_variant (value));
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+g_action_get_property (GObject *object, guint prop_id,
+                       GValue *value, GParamSpec *pspec)
+{
+  GAction *action = G_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_NAME:
+      g_value_set_string (value, g_action_get_name (action));
+      break;
+
+    case PROP_PARAMETER_TYPE:
+      g_value_set_boxed (value, g_action_get_parameter_type (action));
+      break;
+
+    case PROP_ENABLED:
+      g_value_set_boolean (value, g_action_get_enabled (action));
+      break;
+
+    case PROP_STATE_TYPE:
+      g_value_set_boxed (value, g_action_get_state_type (action));
+      break;
+
+    case PROP_STATE_RANGE:
+      g_value_set_variant (value, g_action_get_state_range (action));
+      break;
+
+    case PROP_STATE:
+      g_value_set_variant (value, g_action_get_state (action));
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+g_action_finalize (GObject *object)
+{
+  GAction *action = G_ACTION (object);
+
+  g_free (action->priv->name);
+  if (action->priv->parameter_type)
+    g_variant_type_free (action->priv->parameter_type);
+  if (action->priv->state_type)
+    g_variant_type_free (action->priv->state_type);
+  if (action->priv->state_range)
+    g_variant_unref (action->priv->state_range);
+  if (action->priv->state)
+    g_variant_unref (action->priv->state);
+
+  G_OBJECT_CLASS (g_action_parent_class)
+    ->finalize (object);
+}
+
+void
+g_action_init (GAction *action)
+{
+  action->priv = G_TYPE_INSTANCE_GET_PRIVATE (action,
+                                              G_TYPE_ACTION,
+                                              GActionPrivate);
+}
+
+void
+g_action_class_init (GActionClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->get_property = g_action_get_property;
+  object_class->set_property = g_action_set_property;
+  object_class->finalize = g_action_finalize;
+
+  g_action_signals[SIGNAL_ACTIVATE] =
+    g_signal_new ("activate", G_TYPE_ACTION, G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GActionClass, activate),
+                  NULL, NULL, g_cclosure_marshal_VOID__VARIANT,
+                  G_TYPE_NONE, 1, G_TYPE_VARIANT);
+
+  g_object_class_install_property (object_class, PROP_NAME,
+    g_param_spec_string ("name", "action name",
+                         "the name used to invoke the action",
+                         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_PARAMETER_TYPE,
+    g_param_spec_boxed ("parameter-type", "parameter type",
+                        "the type of GVariant passed to activate()",
+                        G_TYPE_VARIANT_TYPE, G_PARAM_READWRITE |
+                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_ENABLED,
+    g_param_spec_boolean ("enabled", "enabled",
+                          "if the action can be activated",
+                          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_STATE_TYPE,
+    g_param_spec_boxed ("state-type", "state type",
+                        "the type of the state kept by the action",
+                        G_TYPE_VARIANT_TYPE, G_PARAM_READWRITE |
+                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_STATE_RANGE,
+    g_param_spec_variant ("state-range", "state range",
+                          "the range of possible values for state",
+                          G_VARIANT_TYPE_ARRAY, NULL, G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_STATE,
+    g_param_spec_variant ("state", "state", "the state the action is in",
+                          G_VARIANT_TYPE_ANY, NULL, G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_type_class_add_private (class, sizeof (GActionPrivate));
+}
+
+void
+g_action_set_state (GAction  *action,
+                    GVariant *value)
+{
+  if (action->priv->state == value)
+    return;
+
+  g_return_if_fail (G_IS_ACTION (action));
+  g_return_if_fail ((action->priv->state_type == NULL && value == NULL) ||
+                    g_variant_is_of_type (value, action->priv->state_type));
+
+  g_variant_ref_sink (value);
+
+  if (!action->priv->state || !g_variant_equal (action->priv->state, value))
+    {
+      if (action->priv->state)
+        g_variant_unref (action->priv->state);
+
+      action->priv->state = g_variant_ref (value);
+
+      g_object_notify (G_OBJECT (action), "state");
+    }
+
+  g_variant_unref (value);
+}
+
+GVariant *
+g_action_get_state (GAction *action)
+{
+  g_return_val_if_fail (G_IS_ACTION (action), NULL);
+
+  return action->priv->state;
+}
+
+const gchar *
+g_action_get_name (GAction *action)
+{
+  g_return_val_if_fail (G_IS_ACTION (action), NULL);
+
+  return action->priv->name;
+}
+
+const GVariantType *
+g_action_get_parameter_type (GAction *action)
+{
+  g_return_val_if_fail (G_IS_ACTION (action), NULL);
+
+  return action->priv->parameter_type;
+}
+
+const GVariantType *
+g_action_get_state_type (GAction *action)
+{
+  g_return_val_if_fail (G_IS_ACTION (action), NULL);
+
+  return action->priv->state_type;
+}
+
+GVariant *
+g_action_get_state_range (GAction *action)
+{
+  g_return_val_if_fail (G_IS_ACTION (action), NULL);
+
+  return action->priv->state_range;
+}
+
+gboolean
+g_action_get_enabled (GAction *action)
+{
+  g_return_val_if_fail (G_IS_ACTION (action), FALSE);
+
+  return action->priv->enabled;
+}
+
+void
+g_action_set_enabled (GAction  *action,
+                      gboolean  enabled)
+{
+  g_return_if_fail (G_IS_ACTION (action));
+
+  enabled = !!enabled;
+
+  if (action->priv->enabled != enabled)
+    {
+      action->priv->enabled = enabled;
+      g_object_notify (G_OBJECT (action), "enabled");
+    }
+}
+
+void
+g_action_activate (GAction  *action,
+                   GVariant *parameter)
+{
+  g_return_if_fail (G_IS_ACTION (action));
+
+  g_return_if_fail (action->priv->parameter_type == NULL ?
+                      parameter == NULL :
+                    (parameter != NULL &&
+                     g_variant_is_of_type (parameter,
+                                           action->priv->parameter_type)));
+
+  if (action->priv->enabled)
+    g_signal_emit (action, g_action_signals[SIGNAL_ACTIVATE], 0, parameter);
+}
+
+GAction *
+g_action_new (const gchar        *name,
+              const GVariantType *parameter_type)
+{
+  return g_object_new (G_TYPE_ACTION,
+                       "name", name,
+                       "parameter-type", parameter_type,
+                       NULL);
+}
diff --git a/gio/gaction.h b/gio/gaction.h
new file mode 100644
index 0000000..6a8b953
--- /dev/null
+++ b/gio/gaction.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ *
+ * This program 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 licence 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_ACTION_H__
+#define __G_ACTION_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_ACTION                                       (g_action_get_type ())
+#define G_ACTION(inst)                                      (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_ACTION, GAction))
+#define G_ACTION_CLASS(class)                               (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_ACTION, GActionClass))
+#define G_IS_ACTION(inst)                                   (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_ACTION))
+#define G_IS_ACTION_CLASS(class)                            (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_ACTION))
+#define G_ACTION_GET_CLASS(inst)                            (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_ACTION, GActionClass))
+
+typedef struct _GActionPrivate                              GActionPrivate;
+typedef struct _GActionClass                                GActionClass;
+
+/**
+ * GAction:
+ *
+ * The <structname>GAction</structname> structure contains private
+ * data and should only be accessed using the provided API
+ *
+ * Since: 2.26
+ */
+struct _GAction
+{
+  /*< private >*/
+  GObject parent_instance;
+
+  GActionPrivate *priv;
+};
+
+/**
+ * GActionClass:
+ *
+ * The <structname>GActionClass</structname> structure contains
+ * private data only
+ *
+ * Since: 2.26
+ */
+struct _GActionClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+
+  /*< public >*/
+  void (* activate) (GAction  *action,
+                     GVariant *parameter);
+
+  /*< private >*/
+  gpointer padding[12];
+};
+
+GType                   g_action_get_type                               (void) G_GNUC_CONST;
+
+GAction *               g_action_new                                    (const gchar        *name,
+                                                                         const GVariantType *parameter_type);
+
+GAction *               g_action_new_stateful                           (const gchar        *name,
+                                                                         const GVariantType *parameter_type,
+                                                                         const GVariantType *state_type,
+                                                                         GVariant           *state_range,
+                                                                         GVariant           *state);
+
+const gchar *           g_action_get_name                               (GAction           *action);
+const GVariantType *    g_action_get_parameter_type                     (GAction           *action);
+const GVariantType *    g_action_get_state_type                         (GAction           *action);
+GVariant *              g_action_get_state_range                        (GAction           *action);
+
+gboolean                g_action_get_enabled                            (GAction            *action);
+void                    g_action_set_enabled                            (GAction            *action,
+                                                                         gboolean            enabled);
+
+GVariant *              g_action_get_state                              (GAction            *action);
+void                    g_action_set_state                              (GAction            *action,
+                                                                         GVariant           *value);
+
+void                    g_action_activate                               (GAction            *action,
+                                                                         GVariant           *parameter);
+G_END_DECLS
+
+#endif /* __G_ACTION_H__ */
diff --git a/gio/gio.h b/gio/gio.h
index a80ed84..8cbdc0c 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -28,6 +28,7 @@
 #include <gio/giotypes.h>
 
 #include <gio/gappinfo.h>
+#include <gio/gaction.h>
 #include <gio/gapplication.h>
 #include <gio/gasyncinitable.h>
 #include <gio/gasyncresult.h>
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 64b730b..8394e8e 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -47,6 +47,7 @@ typedef struct _GSimplePermission             GSimplePermission;
 typedef struct _GZlibCompressor               GZlibCompressor;
 typedef struct _GZlibDecompressor             GZlibDecompressor;
 
+typedef struct _GAction                       GAction;
 typedef struct _GApplication                  GApplication;
 typedef struct _GApplicationCommandLine       GApplicationCommandLine;
 typedef struct _GSettingsBackend              GSettingsBackend;
diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore
index 8b9e2ce..6cd873f 100644
--- a/gio/tests/.gitignore
+++ b/gio/tests/.gitignore
@@ -1,3 +1,4 @@
+actions
 appinfo
 appinfo-test
 application
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 78fca6d..09927dc 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -23,6 +23,7 @@ progs_ldadd     = 					\
 	$(top_builddir)/gio/libgio-2.0.la
 
 TEST_PROGS +=	 		\
+	actions 		\
 	memory-input-stream 	\
 	memory-output-stream 	\
 	readwrite		\
@@ -98,6 +99,8 @@ if OS_WIN32
 TEST_PROGS += win32-streams
 endif
 
+actions_LDADD	  = $(progs_ldadd)
+
 memory_input_stream_SOURCES	  = memory-input-stream.c
 memory_input_stream_LDADD	  = $(progs_ldadd)
 
diff --git a/gio/tests/actions.c b/gio/tests/actions.c
new file mode 100644
index 0000000..326bb59
--- /dev/null
+++ b/gio/tests/actions.c
@@ -0,0 +1,81 @@
+#include <gio/gio.h>
+#include <stdlib.h>
+
+typedef struct
+{
+  GVariant *params;
+  gboolean did_run;
+} Activation;
+
+static void
+activate (GAction  *action,
+          GVariant *parameter,
+          gpointer  user_data)
+{
+  Activation *activation = user_data;
+
+  if (parameter)
+    activation->params = g_variant_ref (parameter);
+  else
+    activation->params = NULL;
+  activation->did_run = TRUE;
+}
+
+static void
+test_basic (void)
+{
+  Activation a = { 0, };
+  GAction *action;
+
+  action = g_action_new ("foo", NULL);
+  g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
+  g_assert (!a.did_run);
+  g_action_activate (action, NULL);
+  g_assert (a.did_run);
+  a.did_run = FALSE;
+
+  g_action_set_enabled (action, FALSE);
+  g_action_activate (action, NULL);
+  g_assert (!a.did_run);
+
+  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
+    {
+      g_action_activate (action, g_variant_new_string ("xxx"));
+      exit (0);
+    }
+  g_test_trap_assert_failed ();
+
+  g_object_unref (action);
+  g_assert (!a.did_run);
+
+  action = g_action_new ("foo", G_VARIANT_TYPE_STRING);
+  g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
+  g_assert (!a.did_run);
+  g_action_activate (action, g_variant_new_string ("Hello world"));
+  g_assert (a.did_run);
+  g_assert_cmpstr (g_variant_get_string (a.params, NULL), ==, "Hello world");
+  g_variant_unref (a.params);
+  a.did_run = FALSE;
+
+  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
+    {
+      g_action_activate (action, NULL);
+      exit (0);
+    }
+
+  g_test_trap_assert_failed ();
+
+  g_object_unref (action);
+  g_assert (!a.did_run);
+}
+
+int
+main (int argc, char **argv)
+{
+  g_type_init ();
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/actions/basic", test_basic);
+
+  return g_test_run ();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]