[gnome-builder/fix-command-bar] commands: use proposed Gtk API to simplify command resolution
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/fix-command-bar] commands: use proposed Gtk API to simplify command resolution
- Date: Thu, 11 Dec 2014 10:57:58 +0000 (UTC)
commit f173a644b78e684d5a9b896eecf53b2e13cd0f72
Author: Christian Hergert <christian hergert me>
Date: Thu Dec 11 02:57:40 2014 -0800
commands: use proposed Gtk API to simplify command resolution
src/commands/gb-command-gaction-provider.c | 303 ++++++++++++----------------
src/commands/gb-command-gaction.c | 217 ++++++++++++++++++++
src/commands/gb-command-gaction.h | 55 +++++
src/gnome-builder.mk | 2 +
4 files changed, 405 insertions(+), 172 deletions(-)
---
diff --git a/src/commands/gb-command-gaction-provider.c b/src/commands/gb-command-gaction-provider.c
index 2a63558..9a9b514 100644
--- a/src/commands/gb-command-gaction-provider.c
+++ b/src/commands/gb-command-gaction-provider.c
@@ -21,6 +21,7 @@
#include <string.h>
#include "gb-command-gaction-provider.h"
+#include "gb-command-gaction.h"
#include "gb-log.h"
G_DEFINE_TYPE (GbCommandGactionProvider, gb_command_gaction_provider,
@@ -34,246 +35,204 @@ gb_command_gaction_provider_new (GbWorkbench *workbench)
NULL);
}
-static GbCommandResult *
-execute_action (GbCommand *command,
- gpointer user_data)
+static GList *
+discover_groups (GbCommandGactionProvider *provider)
{
- GAction *action;
- GVariant *params;
+ GbDocumentView *view;
+ GApplication *application;
+ GbWorkbench *workbench;
+ GtkWidget *widget;
+ GList *list = NULL;
+
+ g_return_val_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (provider), NULL);
+
+ view = gb_command_provider_get_active_view (GB_COMMAND_PROVIDER (provider));
+
+ g_print ("Active View: %p\n", view);
+ if (view)
+ g_print ("== %s\n", g_type_name (G_TYPE_FROM_INSTANCE (view)));
- g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
+ for (widget = GTK_WIDGET (view);
+ widget;
+ widget = gtk_widget_get_parent (widget))
+ {
+ gchar **prefixes;
+ guint i;
- action = g_object_get_data (G_OBJECT (command), "action");
- g_return_val_if_fail (G_IS_ACTION (action), NULL);
+ prefixes = gtk_widget_list_action_prefixes (widget);
- params = g_object_get_data (G_OBJECT (command), "parameters");
+ if (prefixes)
+ {
+ GActionGroup *group;
- g_action_activate (action, params);
+ for (i = 0; prefixes [i]; i++)
+ {
+ g_print (" Group = %s\n", prefixes [i]);
- return NULL;
+ group = gtk_widget_get_action_group (widget, prefixes [i]);
+
+ if (G_IS_ACTION_GROUP (group))
+ list = g_list_append (list, group);
+ }
+
+ g_strfreev (prefixes);
+ }
+ }
+
+ workbench = gb_command_provider_get_workbench (GB_COMMAND_PROVIDER (provider));
+ list = g_list_append (list, G_ACTION_GROUP (workbench));
+
+ application = g_application_get_default ();
+ list = g_list_append (list, G_ACTION_GROUP (application));
+
+ return list;
}
-static GbCommand *
-gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- const gchar *command_text)
+static gboolean
+parse_command_text (const gchar *command_text,
+ gchar **name,
+ GVariant **params)
{
- GbCommandGactionProvider *self = (GbCommandGactionProvider *)provider;
- GtkWidget *widget;
- GbCommand *command = NULL;
- GVariant *parameters = NULL;
- GAction *action = NULL;
- gchar **parts;
+ GVariant *ret_params = NULL;
+ const gchar *str;
gchar *tmp;
- gchar *name = NULL;
+ gchar **parts;
+ gchar *ret_name = NULL;
- ENTRY;
+ g_return_val_if_fail (command_text, FALSE);
+ g_return_val_if_fail (name, FALSE);
+ g_return_val_if_fail (params, FALSE);
- g_return_val_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (self), NULL);
+ *name = NULL;
+ *params = NULL;
/* Determine the command name */
tmp = g_strdelimit (g_strdup (command_text), "(", ' ');
parts = g_strsplit (tmp, " ", 2);
- name = g_strdup (parts [0]);
+ ret_name = g_strdup (parts [0]);
g_free (tmp);
g_strfreev (parts);
- /* Parse the parameters if provided */
- command_text += strlen (name);
- for (; *command_text; command_text = g_utf8_next_char (command_text))
+ /* Advance to the (optional) parameters */
+ for (str = command_text + strlen (ret_name);
+ *str;
+ str = g_utf8_next_char (str))
{
gunichar ch;
- ch = g_utf8_get_char (command_text);
+ ch = g_utf8_get_char (str);
if (g_unichar_isspace (ch))
continue;
+
break;
}
- if (*command_text)
+ /* Parse any (optional) parameters */
+ if (*str != '\0')
{
- parameters = g_variant_parse (NULL, command_text, NULL, NULL, NULL);
- if (!parameters)
- GOTO (cleanup);
+ ret_params = g_variant_parse (NULL, str, NULL, NULL, NULL);
+ if (!ret_params)
+ goto failure;
}
- /*
- * TODO: We are missing some API in Gtk+ to be able to resolve an action
- * for a particular name. It exists, but is currently only private
- * API. So we'll hold off a bit on this until we can use that.
- * Alternatively, we can just walk up the chain to the
- * ApplicationWindow which is a GActionMap.
- */
+ *name = ret_name;
+ *params = ret_params;
- widget = GTK_WIDGET (gb_command_provider_get_active_view (provider));
- while (widget)
- {
- if (G_IS_ACTION_MAP (widget))
- {
- action = g_action_map_lookup_action (G_ACTION_MAP (widget), name);
- if (action)
- break;
- }
+ return TRUE;
- widget = gtk_widget_get_parent (widget);
- }
+failure:
+ g_clear_pointer (&ret_name, g_free);
+ g_clear_pointer (&ret_params, g_variant_unref);
- /*
- * Now try to lookup the action from the workspace up, which is the case if
- * we don't have an active view.
- */
- if (!action)
- {
- GbWorkbench *workbench;
- GbWorkspace *workspace;
+ return FALSE;
+}
- workbench = gb_command_provider_get_workbench (provider);
- workspace = gb_workbench_get_active_workspace (workbench);
- widget = GTK_WIDGET (workspace);
+static GbCommand *
+gb_command_gaction_provider_lookup (GbCommandProvider *provider,
+ const gchar *command_text)
+{
+ GbCommandGactionProvider *self = (GbCommandGactionProvider *)provider;
+ GbCommand *command = NULL;
+ GVariant *params = NULL;
+ GList *groups;
+ GList *iter;
+ gchar *action_name = NULL;
- while (widget)
- {
- if (G_IS_ACTION_MAP (widget))
- {
- action = g_action_map_lookup_action (G_ACTION_MAP (widget), name);
- if (action)
- break;
- }
- else if (GB_IS_WORKSPACE (widget))
- {
- GActionGroup *group;
-
- group = gb_workspace_get_actions (GB_WORKSPACE (widget));
- if (G_IS_ACTION_MAP (group))
- {
- action = g_action_map_lookup_action (G_ACTION_MAP (group), name);
- if (action)
- break;
- }
- }
+ ENTRY;
- widget = gtk_widget_get_parent (widget);
- }
- }
+ g_return_val_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (self), NULL);
+ g_return_val_if_fail (command_text, NULL);
- /*
- * Now try to lookup the action inside of the GApplication.
- * This is useful for stuff like "quit", and "preferences".
- */
- if (!action)
- {
- GApplication *app;
+ if (!parse_command_text (command_text, &action_name, ¶ms))
+ RETURN (NULL);
- app = g_application_get_default ();
- action = g_action_map_lookup_action (G_ACTION_MAP (app), name);
- }
+ groups = discover_groups (self);
- if (!action && parameters)
+ for (iter = groups; iter; iter = iter->next)
{
- g_variant_unref (parameters);
- parameters = NULL;
- }
+ GActionGroup *group = G_ACTION_GROUP (iter->data);
- if (action)
- {
- command = gb_command_new ();
- if (parameters)
- g_object_set_data_full (G_OBJECT (command), "parameters",
- g_variant_ref (parameters),
- (GDestroyNotify)g_variant_unref);
- g_object_set_data_full (G_OBJECT (command), "action",
- g_object_ref (action), g_object_unref);
- g_signal_connect (command, "execute", G_CALLBACK (execute_action), NULL);
+ if (g_action_group_has_action (group, action_name))
+ {
+ command = g_object_new (GB_TYPE_COMMAND_GACTION,
+ "action-group", group,
+ "action-name", action_name,
+ "parameters", params,
+ NULL);
+ break;
+ }
}
-
-cleanup:
- g_free (name);
+ g_clear_pointer (¶ms, g_variant_unref);
+ g_list_free (groups);
+ g_free (action_name);
RETURN (command);
}
static void
-add_completions_from_group (GPtrArray *completions,
- const gchar *prefix,
- GActionGroup *group)
-{
- gchar **actions = g_action_group_list_actions (group);
- int i;
-
- for (i = 0; actions[i] != NULL; i++)
- {
- if (g_str_has_prefix (actions[i], prefix))
- g_ptr_array_add (completions, g_strdup (actions[i]));
- }
-
- g_strfreev (actions);
-}
-
-static void
gb_command_gaction_provider_complete (GbCommandProvider *provider,
GPtrArray *completions,
const gchar *initial_command_text)
{
GbCommandGactionProvider *self = (GbCommandGactionProvider *)provider;
- GtkWidget *widget;
- const gchar *tmp;
- gchar *prefix;
- GApplication *app;
- GbWorkbench *workbench;
- GbWorkspace *workspace;
+ GList *groups;
+ GList *iter;
ENTRY;
g_return_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (self));
+ g_return_if_fail (initial_command_text);
- tmp = initial_command_text;
-
- while (*tmp != 0 && *tmp != ' ' && *tmp != '(')
- tmp++;
-
- if (*tmp != 0)
- return;
+ g_print ("initial=\"%s\"\n", initial_command_text);
- prefix = g_strndup (initial_command_text, tmp - initial_command_text);
+ groups = discover_groups (self);
- widget = GTK_WIDGET (gb_command_provider_get_active_view (provider));
- while (widget)
+ for (iter = groups; iter; iter = iter->next)
{
- if (G_IS_ACTION_GROUP (widget))
- add_completions_from_group (completions, prefix, G_ACTION_GROUP (widget));
+ GActionGroup *group = iter->data;
+ gchar **names;
+ guint i;
- widget = gtk_widget_get_parent (widget);
- }
+ g_assert (G_IS_ACTION_GROUP (group));
- /*
- * Now try to lookup the action from the workspace up, which is the case if
- * we don't have an active view.
- */
- workbench = gb_command_provider_get_workbench (provider);
- workspace = gb_workbench_get_active_workspace (workbench);
- widget = GTK_WIDGET (workspace);
+ g_print ("Group %p\n", group);
- while (widget)
- {
- if (G_IS_ACTION_GROUP (widget))
- add_completions_from_group (completions, prefix, G_ACTION_GROUP (widget));
- else if (GB_IS_WORKSPACE (widget))
- add_completions_from_group (completions, prefix,
- gb_workspace_get_actions (GB_WORKSPACE (widget)));
+ names = g_action_group_list_actions (group);
- widget = gtk_widget_get_parent (widget);
- }
+ for (i = 0; names [i]; i++)
+ {
+ g_print ("> %s\n", names[i]);
+ if (g_str_has_prefix (names [i], initial_command_text))
+ g_ptr_array_add (completions, g_strdup (names [i]));
+ }
- /*
- * Now try to lookup the action inside of the GApplication.
- * This is useful for stuff like "quit", and "preferences".
- */
- app = g_application_get_default ();
- add_completions_from_group (completions, prefix, G_ACTION_GROUP (app));
+ //g_free (names);
+ }
- g_free (prefix);
+ g_list_free (groups);
- RETURN();
+ EXIT;
}
static void
diff --git a/src/commands/gb-command-gaction.c b/src/commands/gb-command-gaction.c
new file mode 100644
index 0000000..bd34b96
--- /dev/null
+++ b/src/commands/gb-command-gaction.c
@@ -0,0 +1,217 @@
+/* gb-command-gaction.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "command-gaction"
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "gb-command-gaction.h"
+
+struct _GbCommandGactionPrivate
+{
+ GActionGroup *action_group;
+ gchar *action_name;
+ GVariant *parameters;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommandGaction, gb_command_gaction,
+ GB_TYPE_COMMAND)
+
+enum {
+ PROP_0,
+ PROP_ACTION_GROUP,
+ PROP_ACTION_NAME,
+ PROP_PARAMETERS,
+ LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+static void
+gb_command_gaction_set_action_group (GbCommandGaction *gaction,
+ GActionGroup *action_group)
+{
+ g_return_if_fail (GB_IS_COMMAND_GACTION (gaction));
+ g_return_if_fail (G_IS_ACTION_GROUP (action_group));
+
+ if (gaction->priv->action_group != action_group)
+ {
+ g_clear_object (&gaction->priv->action_group);
+ gaction->priv->action_group = g_object_ref (action_group);
+ }
+}
+
+static void
+gb_command_gaction_set_action_name (GbCommandGaction *gaction,
+ const gchar *action_name)
+{
+ g_return_if_fail (GB_IS_COMMAND_GACTION (gaction));
+
+ if (gaction->priv->action_name != action_name)
+ {
+ g_clear_pointer (&gaction->priv->action_name, g_free);
+ gaction->priv->action_name = g_strdup (action_name);
+ }
+}
+
+static void
+gb_command_gaction_set_parameters (GbCommandGaction *gaction,
+ GVariant *variant)
+{
+ g_return_if_fail (GB_IS_COMMAND_GACTION (gaction));
+
+ if (gaction->priv->parameters != variant)
+ {
+ g_clear_pointer (&gaction->priv->parameters, g_variant_unref);
+ gaction->priv->parameters = g_variant_ref (variant);
+ }
+}
+
+static GbCommandResult *
+gb_command_gaction_execute (GbCommand *command)
+{
+ GbCommandGaction *self = (GbCommandGaction *)command;
+
+ g_return_val_if_fail (GB_IS_COMMAND_GACTION (self), NULL);
+
+ if (self->priv->action_group &&
+ self->priv->action_name &&
+ g_action_group_has_action (self->priv->action_group,
+ self->priv->action_name))
+ {
+ g_action_group_activate_action (self->priv->action_group,
+ self->priv->action_name,
+ self->priv->parameters);
+ }
+
+ return NULL;
+}
+
+static void
+gb_command_gaction_finalize (GObject *object)
+{
+ GbCommandGactionPrivate *priv = GB_COMMAND_GACTION (object)->priv;
+
+ g_clear_object (&priv->action_group);
+ g_clear_pointer (&priv->action_name, g_free);
+ g_clear_pointer (&priv->parameters, g_variant_unref);
+
+ G_OBJECT_CLASS (gb_command_gaction_parent_class)->finalize (object);
+}
+
+static void
+gb_command_gaction_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbCommandGaction *self = GB_COMMAND_GACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTION_GROUP:
+ g_value_set_object (value, self->priv->action_group);
+ break;
+
+ case PROP_ACTION_NAME:
+ g_value_set_string (value, self->priv->action_name);
+ break;
+
+ case PROP_PARAMETERS:
+ g_value_set_variant (value, self->priv->parameters);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_command_gaction_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbCommandGaction *self = GB_COMMAND_GACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTION_GROUP:
+ gb_command_gaction_set_action_group (self, g_value_get_object (value));
+ break;
+
+ case PROP_ACTION_NAME:
+ gb_command_gaction_set_action_name (self, g_value_get_string (value));
+ break;
+
+ case PROP_PARAMETERS:
+ gb_command_gaction_set_parameters (self, g_value_get_variant (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_command_gaction_class_init (GbCommandGactionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GbCommandClass *command_class = GB_COMMAND_CLASS (klass);
+
+ object_class->finalize = gb_command_gaction_finalize;
+ object_class->get_property = gb_command_gaction_get_property;
+ object_class->set_property = gb_command_gaction_set_property;
+
+ command_class->execute = gb_command_gaction_execute;
+
+ gParamSpecs [PROP_ACTION_GROUP] =
+ g_param_spec_object ("action-group",
+ _("Action Group"),
+ _("The GActionGroup containing the action."),
+ G_TYPE_ACTION_GROUP,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_ACTION_GROUP,
+ gParamSpecs [PROP_ACTION_GROUP]);
+
+ gParamSpecs [PROP_ACTION_NAME] =
+ g_param_spec_string ("action-name",
+ _("Action Name"),
+ _("The name of the action to execute."),
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_ACTION_NAME,
+ gParamSpecs [PROP_ACTION_NAME]);
+
+ gParamSpecs [PROP_PARAMETERS] =
+ g_param_spec_variant ("parameters",
+ _("Parameters"),
+ _("The parameters for the action."),
+ G_VARIANT_TYPE_ANY,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_PARAMETERS,
+ gParamSpecs [PROP_PARAMETERS]);
+}
+
+static void
+gb_command_gaction_init (GbCommandGaction *self)
+{
+ self->priv = gb_command_gaction_get_instance_private (self);
+}
diff --git a/src/commands/gb-command-gaction.h b/src/commands/gb-command-gaction.h
new file mode 100644
index 0000000..942ad0e
--- /dev/null
+++ b/src/commands/gb-command-gaction.h
@@ -0,0 +1,55 @@
+/* gb-command-gaction.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_COMMAND_GACTION_H
+#define GB_COMMAND_GACTION_H
+
+#include "gb-command.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_COMMAND_GACTION (gb_command_gaction_get_type())
+#define GB_COMMAND_GACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_GACTION,
GbCommandGaction))
+#define GB_COMMAND_GACTION_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_GACTION,
GbCommandGaction const))
+#define GB_COMMAND_GACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GB_TYPE_COMMAND_GACTION,
GbCommandGactionClass))
+#define GB_IS_COMMAND_GACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_COMMAND_GACTION))
+#define GB_IS_COMMAND_GACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GB_TYPE_COMMAND_GACTION))
+#define GB_COMMAND_GACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GB_TYPE_COMMAND_GACTION,
GbCommandGactionClass))
+
+typedef struct _GbCommandGaction GbCommandGaction;
+typedef struct _GbCommandGactionClass GbCommandGactionClass;
+typedef struct _GbCommandGactionPrivate GbCommandGactionPrivate;
+
+struct _GbCommandGaction
+{
+ GbCommand parent;
+
+ /*< private >*/
+ GbCommandGactionPrivate *priv;
+};
+
+struct _GbCommandGactionClass
+{
+ GbCommandClass parent;
+};
+
+GType gb_command_gaction_get_type (void);
+
+G_END_DECLS
+
+#endif /* GB_COMMAND_GACTION_H */
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 55fb7db..73fb02f 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -27,6 +27,8 @@ libgnome_builder_la_SOURCES = \
src/commands/gb-command-bar.h \
src/commands/gb-command-bar-item.c \
src/commands/gb-command-bar-item.h \
+ src/commands/gb-command-gaction.c \
+ src/commands/gb-command-gaction.h \
src/commands/gb-command-gaction-provider.c \
src/commands/gb-command-gaction-provider.h \
src/commands/gb-command-manager.c \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]