[gnome-builder/wip/commands2: 6/12] commands: some work on gaction command execution.
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/commands2: 6/12] commands: some work on gaction command execution.
- Date: Fri, 10 Oct 2014 01:05:15 +0000 (UTC)
commit cbcb2d0989e94927fa1957f93ac229eed468ae1d
Author: Christian Hergert <christian hergert me>
Date: Thu Oct 9 14:22:26 2014 -0700
commands: some work on gaction command execution.
We can't do this as good as I'd like yet, do to some missing API in Gtk.
But we'll get there eventually.
Additionally, it will require prefixes right now, which I'd like to avoid
in the future if possible so we can do "save" instead of "editor.save".
src/commands/gb-command-gaction-provider.c | 165 ++++++++++++++++++++++++++++
1 files changed, 165 insertions(+), 0 deletions(-)
---
diff --git a/src/commands/gb-command-gaction-provider.c b/src/commands/gb-command-gaction-provider.c
index 20db506..028b5b4 100644
--- a/src/commands/gb-command-gaction-provider.c
+++ b/src/commands/gb-command-gaction-provider.c
@@ -16,13 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define G_LOG_DOMAIN "gaction-commands"
+
#include <glib/gi18n.h>
#include "gb-command-gaction-provider.h"
+#include "gb-tab.h"
struct _GbCommandGactionProviderPrivate
{
GbWorkbench *workbench;
+ GtkWidget *focus;
};
G_DEFINE_TYPE_WITH_PRIVATE (GbCommandGactionProvider,
@@ -53,6 +57,84 @@ gb_command_gaction_provider_get_workbench (GbCommandGactionProvider *provider)
return provider->priv->workbench;
}
+static void
+gb_command_gaction_provider_update_focus (GbCommandGactionProvider *provider,
+ GtkWidget *focus)
+{
+ GbCommandGactionProviderPrivate *priv;
+
+ g_return_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (provider));
+ g_return_if_fail (!focus || GTK_IS_WIDGET (focus));
+
+ priv = provider->priv;
+
+ if (priv->focus)
+ {
+ g_object_remove_weak_pointer (G_OBJECT (priv->focus),
+ (gpointer *)&priv->focus);
+ priv->focus = NULL;
+ }
+
+ if (focus)
+ {
+ priv->focus = focus;
+ g_object_add_weak_pointer (G_OBJECT (priv->focus),
+ (gpointer *)&priv->focus);
+ }
+}
+
+static void
+on_workbench_set_focus (GbCommandGactionProvider *provider,
+ GtkWidget *widget,
+ GbWorkbench *workbench)
+{
+ GtkWidget *parent = widget;
+
+ g_return_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (provider));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ /*
+ * Try to locate the nearest GbTab in the widget hierarchy starting from
+ * the new focus widget. If this widget is not a decendent of a tab, we
+ * will just ignore things.
+ */
+ while (!GB_IS_TAB (parent))
+ {
+ parent = gtk_widget_get_parent (parent);
+ if (!parent)
+ break;
+ }
+
+ if (GB_IS_TAB (parent))
+ gb_command_gaction_provider_update_focus (provider, parent);
+}
+
+static void
+gb_command_gaction_provider_connect (GbCommandGactionProvider *provider,
+ GbWorkbench *workbench)
+{
+ g_return_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (provider));
+ g_return_if_fail (GB_IS_WORKBENCH (workbench));
+
+ g_signal_connect_object (workbench,
+ "set-focus",
+ G_CALLBACK (on_workbench_set_focus),
+ provider,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+gb_command_gaction_provider_disconnect (GbCommandGactionProvider *provider,
+ GbWorkbench *workbench)
+{
+ g_return_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (provider));
+ g_return_if_fail (GB_IS_WORKBENCH (workbench));
+
+ g_signal_handlers_disconnect_by_func (workbench,
+ G_CALLBACK (on_workbench_set_focus),
+ provider);
+}
+
void
gb_command_gaction_provider_set_workbench (GbCommandGactionProvider *provider,
GbWorkbench *workbench)
@@ -68,6 +150,7 @@ gb_command_gaction_provider_set_workbench (GbCommandGactionProvider *provider,
{
if (priv->workbench)
{
+ gb_command_gaction_provider_disconnect (provider, workbench);
g_object_remove_weak_pointer (G_OBJECT (priv->workbench),
(gpointer *)&priv->workbench);
priv->workbench = NULL;
@@ -75,6 +158,7 @@ gb_command_gaction_provider_set_workbench (GbCommandGactionProvider *provider,
if (workbench)
{
+ gb_command_gaction_provider_connect (provider, workbench);
priv->workbench = workbench;
g_object_add_weak_pointer (G_OBJECT (workbench),
(gpointer *)&priv->workbench);
@@ -85,11 +169,89 @@ gb_command_gaction_provider_set_workbench (GbCommandGactionProvider *provider,
}
}
+static GAction *
+gb_command_gaction_provider_lookup (GbCommandProvider *provider,
+ const gchar *command_text,
+ GVariant **parameters)
+{
+ GbCommandGactionProvider *self = (GbCommandGactionProvider *)provider;
+ GtkWidget *widget;
+ GAction *action = NULL;
+ gchar **parts;
+ gchar *tmp;
+ gchar *name = NULL;
+
+ g_return_val_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (self), NULL);
+
+ if (!self->priv->focus)
+ return NULL;
+
+ widget = self->priv->focus;
+
+ /* Determine the command name */
+ tmp = g_strdelimit (g_strdup (command_text), "(", ' ');
+ parts = g_strsplit (tmp, " ", 2);
+ 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))
+ {
+ gunichar ch;
+
+ ch = g_utf8_get_char (command_text);
+ if (g_unichar_isspace (ch))
+ continue;
+ break;
+ }
+
+ if (*command_text)
+ {
+ *parameters = g_variant_parse (NULL, command_text, NULL, NULL, NULL);
+ if (!*parameters)
+ goto cleanup;
+ }
+
+ /*
+ * 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.
+ */
+
+ while (widget)
+ {
+ if (G_IS_ACTION_MAP (widget))
+ {
+ action = g_action_map_lookup_action (G_ACTION_MAP (widget), name);
+ if (action)
+ break;
+ }
+
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ if (!action && *parameters)
+ {
+ g_variant_unref (*parameters);
+ *parameters = NULL;
+ }
+
+cleanup:
+ g_free (name);
+
+ return action;
+}
+
static void
gb_command_gaction_provider_dispose (GObject *object)
{
GbCommandGactionProvider *provider = (GbCommandGactionProvider *)object;
+ gb_command_gaction_provider_update_focus (provider, NULL);
gb_command_gaction_provider_set_workbench (provider, NULL);
G_OBJECT_CLASS (gb_command_gaction_provider_parent_class)->dispose (object);
@@ -139,11 +301,14 @@ static void
gb_command_gaction_provider_class_init (GbCommandGactionProviderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GbCommandProviderClass *provider_class = GB_COMMAND_PROVIDER_CLASS (klass);
object_class->dispose = gb_command_gaction_provider_dispose;
object_class->get_property = gb_command_gaction_provider_get_property;
object_class->set_property = gb_command_gaction_provider_set_property;
+ provider_class->lookup = gb_command_gaction_provider_lookup;
+
gParamSpecs [PROP_WORKBENCH] =
g_param_spec_object ("workbench",
_("Workbench"),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]