[gnome-builder: 69/139] command-bar: port command bar to libide-editor
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder: 69/139] command-bar: port command bar to libide-editor
- Date: Thu, 10 Jan 2019 04:23:07 +0000 (UTC)
commit c42c8ec7dfb0123c3c5612ef0850490a227fc2c2
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 9 17:11:13 2019 -0800
command-bar: port command bar to libide-editor
This also implements a new design as part of this work to make the
command bar front-and-center when used. We have lost a little bit of
features in the process (naming the tab completion still needs work as
well as dyanmic data such as %s/foo/bar).
We expect more changes in this plugin in the future as design work
fleshes out more of a command bar experience.
src/plugins/command-bar/command-bar-plugin.c | 40 +
src/plugins/command-bar/command-bar.gresource.xml | 8 +
src/plugins/command-bar/command-bar.plugin | 12 +-
src/plugins/command-bar/gb-command-bar.c | 774 ---------
.../command-bar/gb-command-bar.gresource.xml | 11 -
src/plugins/command-bar/gb-command-bar.ui | 87 -
.../command-bar/gb-command-gaction-provider.c | 475 ------
src/plugins/command-bar/gb-command-gaction.c | 210 ---
src/plugins/command-bar/gb-command-manager.c | 164 --
src/plugins/command-bar/gb-command-manager.h | 42 -
src/plugins/command-bar/gb-command-provider.c | 427 -----
src/plugins/command-bar/gb-command-provider.h | 57 -
src/plugins/command-bar/gb-command-result.c | 264 ----
src/plugins/command-bar/gb-command-result.h | 45 -
src/plugins/command-bar/gb-command-vim-provider.c | 106 --
src/plugins/command-bar/gb-command-vim.c | 202 ---
src/plugins/command-bar/gb-command.c | 72 -
src/plugins/command-bar/gb-command.h | 43 -
src/plugins/command-bar/gb-vim.c | 1663 --------------------
src/plugins/command-bar/gb-vim.h | 46 -
.../command-bar/gbp-command-bar-command-provider.c | 198 +++
...ovider.h => gbp-command-bar-command-provider.h} | 11 +-
src/plugins/command-bar/gbp-command-bar-model.c | 236 +++
src/plugins/command-bar/gbp-command-bar-model.h | 42 +
...{gb-command-vim.h => gbp-command-bar-private.h} | 10 +-
.../command-bar/gbp-command-bar-shortcuts.c | 64 +
.../command-bar/gbp-command-bar-suggestion.c | 156 ++
...ion-provider.h => gbp-command-bar-suggestion.h} | 15 +-
.../command-bar/gbp-command-bar-workspace-addin.c | 165 ++
...gaction.h => gbp-command-bar-workspace-addin.h} | 10 +-
src/plugins/command-bar/gbp-command-bar.c | 294 ++++
.../{gb-command-bar.h => gbp-command-bar.h} | 14 +-
src/plugins/command-bar/gbp-command-bar.ui | 18 +
src/plugins/command-bar/gbp-gaction-command.c | 160 ++
src/plugins/command-bar/gbp-gaction-command.h | 40 +
src/plugins/command-bar/meson.build | 47 +-
src/plugins/command-bar/themes/shared.css | 33 +-
37 files changed, 1475 insertions(+), 4786 deletions(-)
---
diff --git a/src/plugins/command-bar/command-bar-plugin.c b/src/plugins/command-bar/command-bar-plugin.c
new file mode 100644
index 000000000..748ccd2a0
--- /dev/null
+++ b/src/plugins/command-bar/command-bar-plugin.c
@@ -0,0 +1,40 @@
+/* command-bar-plugin.c
+ *
+ * Copyright 2015-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "command-bar-plugin"
+
+#include "config.h"
+
+#include <libide-gui.h>
+#include <libpeas/peas.h>
+
+#include "gbp-command-bar-command-provider.h"
+#include "gbp-command-bar-workspace-addin.h"
+
+void
+_gbp_command_bar_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_COMMAND_PROVIDER,
+ GBP_TYPE_COMMAND_BAR_COMMAND_PROVIDER);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_WORKSPACE_ADDIN,
+ GBP_TYPE_COMMAND_BAR_WORKSPACE_ADDIN);
+}
diff --git a/src/plugins/command-bar/command-bar.gresource.xml
b/src/plugins/command-bar/command-bar.gresource.xml
new file mode 100644
index 000000000..f20869f4c
--- /dev/null
+++ b/src/plugins/command-bar/command-bar.gresource.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/plugins/command-bar">
+ <file>command-bar.plugin</file>
+ <file>themes/shared.css</file>
+ <file preprocess="xml-stripblanks">gbp-command-bar.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/plugins/command-bar/command-bar.plugin b/src/plugins/command-bar/command-bar.plugin
index 48ea3d0ef..2a0b145a3 100644
--- a/src/plugins/command-bar/command-bar.plugin
+++ b/src/plugins/command-bar/command-bar.plugin
@@ -1,9 +1,11 @@
[Plugin]
-Module=command-bar
-Name=Command Bar
-Description=Provides a command bar at the bottom of the workbench window.
Authors=Christian Hergert <christian hergert me>
-Copyright=Copyright © 2015 Christian Hergert
Builtin=true
+Copyright=Copyright © 2014-2018 Christian Hergert
+Depends=editor;terminal;
+Description=Builder's workspace command-bar
+Embedded=_gbp_command_bar_register_types
Hidden=true
-Embedded=gb_command_bar_register_types
+Module=command-bar
+Name=Command Bar
+X-Workspace-Kind=primary;editor;terminal;
diff --git a/src/plugins/command-bar/gbp-command-bar-command-provider.c
b/src/plugins/command-bar/gbp-command-bar-command-provider.c
new file mode 100644
index 000000000..3eca2a278
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar-command-provider.c
@@ -0,0 +1,198 @@
+/* gbp-command-bar-command-provider.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-command-bar-command-provider"
+
+#include <libide-gui.h>
+#include <libide-sourceview.h>
+#include <libide-threading.h>
+
+#include "gbp-command-bar-command-provider.h"
+#include "gbp-gaction-command.h"
+
+struct _GbpCommandBarCommandProvider
+{
+ GObject parent_instance;
+};
+
+static gint
+sort_actions_by_priority (gconstpointer a,
+ gconstpointer b)
+{
+ GbpGactionCommand *cmd_a = *(GbpGactionCommand **)a;
+ GbpGactionCommand *cmd_b = *(GbpGactionCommand **)b;
+
+ return gbp_gaction_command_compare (cmd_a, cmd_b);
+}
+
+static void
+add_from_group (const gchar *needle,
+ GPtrArray *results,
+ const gchar *prefix,
+ GtkWidget *widget,
+ GActionGroup *group,
+ GHashTable *seen)
+{
+ g_auto(GStrv) actions = NULL;
+
+ g_assert (needle != NULL);
+ g_assert (results != NULL);
+ g_assert (prefix != NULL);
+ g_assert (GTK_IS_WIDGET (widget));
+ g_assert (G_IS_ACTION_GROUP (group));
+
+ /* Skip source-view actions which bridge to signals */
+ if (g_str_equal (prefix, "source-view"))
+ return;
+
+ actions = g_action_group_list_actions (group);
+
+ for (guint j = 0; actions[j]; j++)
+ {
+ g_autofree gchar *title = NULL;
+ const GVariantType *type;
+ GbpGactionCommand *command;
+ guint priority = 0;
+
+ if (g_hash_table_contains (seen, actions[j]))
+ continue;
+
+ g_hash_table_insert (seen, g_strdup (actions[j]), NULL);
+
+ /* Skip actions with params */
+ if ((type = g_action_group_get_action_parameter_type (group, actions[j])))
+ continue;
+
+ if (!ide_completion_fuzzy_match (actions[j], needle, &priority))
+ continue;
+
+ title = ide_completion_fuzzy_highlight (actions[j], needle);
+ command = gbp_gaction_command_new (widget, prefix, actions[j], NULL, title, priority);
+ g_ptr_array_add (results, g_steal_pointer (&command));
+ }
+}
+
+static void
+populate_gactions_at_widget (const gchar *needle,
+ GPtrArray *results,
+ GtkWidget *widget,
+ GHashTable *seen)
+{
+ g_autofree const gchar **prefixes = NULL;
+ GtkWidget *parent;
+
+ g_assert (results != NULL);
+ g_assert (GTK_IS_WIDGET (widget));
+
+ if ((prefixes = gtk_widget_list_action_prefixes (widget)))
+ {
+ for (guint i = 0; prefixes[i]; i++)
+ {
+ GActionGroup *group;
+
+ if ((group = gtk_widget_get_action_group (widget, prefixes[i])))
+ add_from_group (needle, results, prefixes[i], widget, group, seen);
+ }
+ }
+
+ if ((parent = gtk_widget_get_parent (widget)))
+ populate_gactions_at_widget (needle, results, parent, seen);
+ else
+ add_from_group (needle, results, "app", widget, G_ACTION_GROUP (IDE_APPLICATION_DEFAULT), seen);
+}
+
+static void
+gbp_command_bar_command_provider_query_async (IdeCommandProvider *provider,
+ IdeWorkspace *workspace,
+ const gchar *typed_text,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GbpCommandBarCommandProvider *self = (GbpCommandBarCommandProvider *)provider;
+ g_autoptr(GHashTable) seen = NULL;
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GPtrArray) results = NULL;
+ g_autofree gchar *needle = NULL;
+ IdeSurface *surface;
+ IdePage *page;
+
+ g_assert (GBP_IS_COMMAND_BAR_COMMAND_PROVIDER (self));
+ g_assert (IDE_IS_WORKSPACE (workspace));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_command_bar_command_provider_query_async);
+
+ seen = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ needle = g_utf8_casefold (typed_text, -1);
+ results = g_ptr_array_new_with_free_func (g_object_unref);
+ surface = ide_workspace_get_visible_surface (workspace);
+
+ if ((page = ide_workspace_get_most_recent_page (workspace)))
+ populate_gactions_at_widget (needle, results, GTK_WIDGET (page), seen);
+ else
+ populate_gactions_at_widget (needle, results, GTK_WIDGET (surface), seen);
+
+ g_ptr_array_sort (results, sort_actions_by_priority);
+
+ ide_task_return_pointer (task,
+ g_steal_pointer (&results),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+static GPtrArray *
+gbp_command_bar_command_provider_query_finish (IdeCommandProvider *provider,
+ GAsyncResult *result,
+ GError **error)
+{
+ GbpCommandBarCommandProvider *self = (GbpCommandBarCommandProvider *)provider;
+ GPtrArray *ret;
+
+ g_assert (GBP_IS_COMMAND_BAR_COMMAND_PROVIDER (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+ return IDE_PTR_ARRAY_STEAL_FULL (&ret);
+}
+
+static void
+command_provider_iface_init (IdeCommandProviderInterface *iface)
+{
+ iface->query_async = gbp_command_bar_command_provider_query_async;
+ iface->query_finish = gbp_command_bar_command_provider_query_finish;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpCommandBarCommandProvider,
+ gbp_command_bar_command_provider,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_COMMAND_PROVIDER,
+ command_provider_iface_init))
+
+static void
+gbp_command_bar_command_provider_class_init (GbpCommandBarCommandProviderClass *klass)
+{
+}
+
+static void
+gbp_command_bar_command_provider_init (GbpCommandBarCommandProvider *self)
+{
+}
diff --git a/src/plugins/command-bar/gb-command-vim-provider.h
b/src/plugins/command-bar/gbp-command-bar-command-provider.h
similarity index 68%
rename from src/plugins/command-bar/gb-command-vim-provider.h
rename to src/plugins/command-bar/gbp-command-bar-command-provider.h
index 11e96f4b8..6407b5ad7 100644
--- a/src/plugins/command-bar/gb-command-vim-provider.h
+++ b/src/plugins/command-bar/gbp-command-bar-command-provider.h
@@ -1,6 +1,6 @@
-/* gb-command-vim-provider.h
+/* gbp-command-bar-command-provider.h
*
- * Copyright 2014-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
*
* 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
@@ -20,13 +20,12 @@
#pragma once
-#include "gb-command-provider.h"
+#include <glib-object.h>
G_BEGIN_DECLS
-#define GB_TYPE_COMMAND_VIM_PROVIDER (gb_command_vim_provider_get_type())
+#define GBP_TYPE_COMMAND_BAR_COMMAND_PROVIDER (gbp_command_bar_command_provider_get_type())
-G_DECLARE_FINAL_TYPE (GbCommandVimProvider, gb_command_vim_provider,
- GB, COMMAND_VIM_PROVIDER, GbCommandProvider)
+G_DECLARE_FINAL_TYPE (GbpCommandBarCommandProvider, gbp_command_bar_command_provider, GBP,
COMMAND_BAR_COMMAND_PROVIDER, GObject)
G_END_DECLS
diff --git a/src/plugins/command-bar/gbp-command-bar-model.c b/src/plugins/command-bar/gbp-command-bar-model.c
new file mode 100644
index 000000000..cd773fa05
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar-model.c
@@ -0,0 +1,236 @@
+/* gbp-command-bar-model.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-command-bar-model"
+
+#include "config.h"
+
+#include <libide-gui.h>
+#include <libide-threading.h>
+#include <libpeas/peas.h>
+#include <libpeas/peas-autocleanups.h>
+
+#include "gbp-command-bar-suggestion.h"
+#include "gbp-command-bar-model.h"
+
+struct _GbpCommandBarModel
+{
+ IdeObject parent_instance;
+ GPtrArray *items;
+};
+
+typedef struct
+{
+ IdeWorkspace *workspace;
+ IdeTask *task;
+ const gchar *typed_text;
+ GPtrArray *providers;
+} Complete;
+
+static GType
+gbp_command_bar_model_get_item_type (GListModel *model)
+{
+ return GBP_TYPE_COMMAND_BAR_SUGGESTION;
+}
+
+static guint
+gbp_command_bar_model_get_n_items (GListModel *model)
+{
+ return GBP_COMMAND_BAR_MODEL (model)->items->len;
+}
+
+static gpointer
+gbp_command_bar_model_get_item (GListModel *model,
+ guint position)
+{
+ GbpCommandBarModel *self = (GbpCommandBarModel *)model;
+
+ g_assert (GBP_IS_COMMAND_BAR_MODEL (self));
+
+ if (position < self->items->len)
+ return g_object_ref (g_ptr_array_index (self->items, position));
+
+ return NULL;
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+ iface->get_item_type = gbp_command_bar_model_get_item_type;
+ iface->get_n_items = gbp_command_bar_model_get_n_items;
+ iface->get_item = gbp_command_bar_model_get_item;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpCommandBarModel, gbp_command_bar_model, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
+
+static void
+gbp_command_bar_model_dispose (GObject *object)
+{
+ GbpCommandBarModel *self = (GbpCommandBarModel *)object;
+
+ g_clear_pointer (&self->items, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (gbp_command_bar_model_parent_class)->dispose (object);
+}
+
+static void
+gbp_command_bar_model_class_init (GbpCommandBarModelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gbp_command_bar_model_dispose;
+}
+
+static void
+gbp_command_bar_model_init (GbpCommandBarModel *self)
+{
+ self->items = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+GbpCommandBarModel *
+gbp_command_bar_model_new (IdeContext *context)
+{
+ GbpCommandBarModel *self;
+
+ self = g_object_new (GBP_TYPE_COMMAND_BAR_MODEL, NULL);
+ ide_object_append (IDE_OBJECT (context), IDE_OBJECT (self));
+
+ return g_steal_pointer (&self);
+}
+
+static void
+gbp_command_bar_model_query_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeCommandProvider *provider = (IdeCommandProvider *)object;
+ g_autoptr(GPtrArray) items = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ GbpCommandBarModel *self;
+ GPtrArray *providers;
+ guint position;
+
+ g_assert (IDE_IS_COMMAND_PROVIDER (provider));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ self = ide_task_get_source_object (task);
+ providers = ide_task_get_task_data (task);
+
+ g_assert (GBP_IS_COMMAND_BAR_MODEL (self));
+ g_assert (providers != NULL);
+
+ position = self->items->len;
+
+ if ((items = ide_command_provider_query_finish (provider, result, &error)))
+ {
+ for (guint i = 0; i < items->len; i++)
+ {
+ IdeCommand *command = g_ptr_array_index (items, i);
+
+ g_ptr_array_add (self->items, gbp_command_bar_suggestion_new (command));
+ }
+
+ g_list_model_items_changed (G_LIST_MODEL (self), position, 0, items->len);
+ }
+
+ IDE_PTR_ARRAY_SET_FREE_FUNC (items, g_object_unref);
+
+ g_ptr_array_remove (providers, provider);
+
+ if (providers->len == 0)
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+gbp_command_bar_query_foreach_cb (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ IdeCommandProvider *provider = (IdeCommandProvider *)exten;
+ Complete *complete = user_data;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_COMMAND_PROVIDER (provider));
+ g_assert (complete != NULL);
+
+ g_ptr_array_add (complete->providers, g_object_ref (provider));
+
+ ide_command_provider_query_async (provider,
+ complete->workspace,
+ complete->typed_text,
+ ide_task_get_cancellable (complete->task),
+ gbp_command_bar_model_query_cb,
+ g_object_ref (complete->task));
+}
+
+void
+gbp_command_bar_model_complete_async (GbpCommandBarModel *self,
+ IdeWorkspace *workspace,
+ const gchar *typed_text,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(PeasExtensionSet) set = NULL;
+ g_autoptr(GPtrArray) providers = NULL;
+ g_autoptr(IdeTask) task = NULL;
+ Complete complete = {0};
+
+ g_return_if_fail (GBP_IS_COMMAND_BAR_MODEL (self));
+ g_return_if_fail (IDE_IS_WORKSPACE (workspace));
+ g_return_if_fail (typed_text != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ providers = g_ptr_array_new_with_free_func (g_object_unref);
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_command_bar_model_complete_async);
+ ide_task_set_task_data (task, g_ptr_array_ref (providers), g_ptr_array_unref);
+
+ set = peas_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_COMMAND_PROVIDER,
+ NULL);
+
+ complete.workspace = workspace;
+ complete.providers = providers;
+ complete.typed_text = typed_text;
+ complete.task = task;
+
+ peas_extension_set_foreach (set, gbp_command_bar_query_foreach_cb, &complete);
+
+ if (providers->len == 0)
+ ide_task_return_boolean (task, TRUE);
+}
+
+gboolean
+gbp_command_bar_model_complete_finish (GbpCommandBarModel *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (GBP_IS_COMMAND_BAR_MODEL (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
diff --git a/src/plugins/command-bar/gbp-command-bar-model.h b/src/plugins/command-bar/gbp-command-bar-model.h
new file mode 100644
index 000000000..d1ac820dc
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar-model.h
@@ -0,0 +1,42 @@
+/* gbp-command-bar-model.h
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-gui.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_COMMAND_BAR_MODEL (gbp_command_bar_model_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCommandBarModel, gbp_command_bar_model, GBP, COMMAND_BAR_MODEL, IdeObject)
+
+GbpCommandBarModel *gbp_command_bar_model_new (IdeContext *context);
+void gbp_command_bar_model_complete_async (GbpCommandBarModel *self,
+ IdeWorkspace *workspace,
+ const gchar *typed_text,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_command_bar_model_complete_finish (GbpCommandBarModel *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
diff --git a/src/plugins/command-bar/gb-command-vim.h b/src/plugins/command-bar/gbp-command-bar-private.h
similarity index 75%
rename from src/plugins/command-bar/gb-command-vim.h
rename to src/plugins/command-bar/gbp-command-bar-private.h
index 654807972..8becbab60 100644
--- a/src/plugins/command-bar/gb-command-vim.h
+++ b/src/plugins/command-bar/gbp-command-bar-private.h
@@ -1,6 +1,6 @@
-/* gb-command-vim.h
+/* gbp-command-bar-private.h
*
- * Copyright 2014-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
*
* 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
@@ -20,12 +20,10 @@
#pragma once
-#include "gb-command.h"
+#include "gbp-command-bar.h"
G_BEGIN_DECLS
-#define GB_TYPE_COMMAND_VIM (gb_command_vim_get_type())
-
-G_DECLARE_FINAL_TYPE (GbCommandVim, gb_command_vim, GB, COMMAND_VIM, GbCommand)
+void _gbp_command_bar_init_shortcuts (GbpCommandBar *self);
G_END_DECLS
diff --git a/src/plugins/command-bar/gbp-command-bar-shortcuts.c
b/src/plugins/command-bar/gbp-command-bar-shortcuts.c
new file mode 100644
index 000000000..6e9fb51e6
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar-shortcuts.c
@@ -0,0 +1,64 @@
+/* gbp-command-bar-shortcuts.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-command-bar-shortcuts"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <dazzle.h>
+
+#include "gbp-command-bar-private.h"
+
+#define I_(s) g_intern_static_string(s)
+
+static const DzlShortcutEntry command_bar_shortcuts[] = {
+ { "org.gnome.builder.command-bar.reveal",
+ DZL_SHORTCUT_PHASE_GLOBAL | DZL_SHORTCUT_PHASE_CAPTURE,
+ NULL,
+ NC_("shortcut window", "Workspace Shortcuts"),
+ NC_("shortcut window", "Command Bar"),
+ NC_("shortcut window", "Show the workspace command bar") },
+};
+
+void
+_gbp_command_bar_init_shortcuts (GbpCommandBar *self)
+{
+ DzlShortcutController *controller;
+
+ dzl_shortcut_manager_add_shortcut_entries (NULL,
+ command_bar_shortcuts,
+ G_N_ELEMENTS (command_bar_shortcuts),
+ GETTEXT_PACKAGE);
+
+ controller = dzl_shortcut_controller_find (GTK_WIDGET (self));
+
+ dzl_shortcut_controller_add_command_action (controller,
+ I_("org.gnome.builder.command-bar.reveal"),
+ I_("<Primary>Return"),
+ DZL_SHORTCUT_PHASE_GLOBAL | DZL_SHORTCUT_PHASE_CAPTURE,
+ I_("win.reveal-command-bar"));
+
+ dzl_shortcut_controller_add_command_action (controller,
+ I_("org.gnome.builder.command-bar.dismiss"),
+ I_("Escape"),
+ DZL_SHORTCUT_PHASE_CAPTURE,
+ I_("win.dismiss-command-bar"));
+}
diff --git a/src/plugins/command-bar/gbp-command-bar-suggestion.c
b/src/plugins/command-bar/gbp-command-bar-suggestion.c
new file mode 100644
index 000000000..71a528314
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar-suggestion.c
@@ -0,0 +1,156 @@
+/* gbp-command-bar-suggestion.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-command-bar-suggestion"
+
+#include "config.h"
+
+#include "gbp-command-bar-suggestion.h"
+
+struct _GbpCommandBarSuggestion
+{
+ DzlSuggestion parent_instance;
+ IdeCommand *command;
+} GbpCommandBarSuggestionPrivate;
+
+enum {
+ PROP_0,
+ PROP_COMMAND,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (GbpCommandBarSuggestion, gbp_command_bar_suggestion, DZL_TYPE_SUGGESTION)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_command_bar_suggestion_set_command (GbpCommandBarSuggestion *self,
+ IdeCommand *command)
+{
+ g_return_if_fail (GBP_IS_COMMAND_BAR_SUGGESTION (self));
+ g_return_if_fail (IDE_IS_COMMAND (command));
+
+ if (g_set_object (&self->command, command))
+ {
+ g_autofree gchar *title = ide_command_get_title (command);
+ g_autofree gchar *subtitle = ide_command_get_subtitle (command);
+
+ dzl_suggestion_set_title (DZL_SUGGESTION (self), title);
+ dzl_suggestion_set_subtitle (DZL_SUGGESTION (self), subtitle);
+ }
+}
+
+static void
+gbp_command_bar_suggestion_dispose (GObject *object)
+{
+ GbpCommandBarSuggestion *self = (GbpCommandBarSuggestion *)object;
+
+ g_clear_object (&self->command);
+
+ G_OBJECT_CLASS (gbp_command_bar_suggestion_parent_class)->dispose (object);
+}
+
+static void
+gbp_command_bar_suggestion_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpCommandBarSuggestion *self = GBP_COMMAND_BAR_SUGGESTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_COMMAND:
+ g_value_set_object (value, gbp_command_bar_suggestion_get_command (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_command_bar_suggestion_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbpCommandBarSuggestion *self = GBP_COMMAND_BAR_SUGGESTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_COMMAND:
+ gbp_command_bar_suggestion_set_command (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_command_bar_suggestion_class_init (GbpCommandBarSuggestionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gbp_command_bar_suggestion_dispose;
+ object_class->get_property = gbp_command_bar_suggestion_get_property;
+ object_class->set_property = gbp_command_bar_suggestion_set_property;
+
+ properties [PROP_COMMAND] =
+ g_param_spec_object ("command",
+ "Command",
+ "The command for the suggestion",
+ IDE_TYPE_COMMAND,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_command_bar_suggestion_init (GbpCommandBarSuggestion *self)
+{
+}
+
+/**
+ * gbp_command_bar_suggestion_get_command:
+ * @self: a #GbpCommandBarSuggestion
+ *
+ * Returns: (transfer none): an #IdeCommand
+ *
+ * Since: 3.32
+ */
+IdeCommand *
+gbp_command_bar_suggestion_get_command (GbpCommandBarSuggestion *self)
+{
+ g_return_val_if_fail (GBP_IS_COMMAND_BAR_SUGGESTION (self), NULL);
+
+ return self->command;
+}
+
+GbpCommandBarSuggestion *
+gbp_command_bar_suggestion_new (IdeCommand *command)
+{
+ g_return_val_if_fail (IDE_IS_COMMAND (command), NULL);
+
+ return g_object_new (GBP_TYPE_COMMAND_BAR_SUGGESTION,
+ "command", command,
+ NULL);
+}
diff --git a/src/plugins/command-bar/gb-command-gaction-provider.h
b/src/plugins/command-bar/gbp-command-bar-suggestion.h
similarity index 58%
rename from src/plugins/command-bar/gb-command-gaction-provider.h
rename to src/plugins/command-bar/gbp-command-bar-suggestion.h
index ece68a396..0d4f5bee4 100644
--- a/src/plugins/command-bar/gb-command-gaction-provider.h
+++ b/src/plugins/command-bar/gbp-command-bar-suggestion.h
@@ -1,6 +1,6 @@
-/* gb-command-gaction-provider.h
+/* gbp-command-bar-suggestion.h
*
- * Copyright 2014-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
*
* 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
@@ -20,15 +20,16 @@
#pragma once
-#include "gb-command-provider.h"
+#include <dazzle.h>
+#include <libide-gui.h>
G_BEGIN_DECLS
-#define GB_TYPE_COMMAND_GACTION_PROVIDER (gb_command_gaction_provider_get_type())
+#define GBP_TYPE_COMMAND_BAR_SUGGESTION (gbp_command_bar_suggestion_get_type())
-G_DECLARE_FINAL_TYPE (GbCommandGactionProvider, gb_command_gaction_provider,
- GB, COMMAND_GACTION_PROVIDER, GbCommandProvider)
+G_DECLARE_FINAL_TYPE (GbpCommandBarSuggestion, gbp_command_bar_suggestion, GBP, COMMAND_BAR_SUGGESTION,
DzlSuggestion)
-GbCommandProvider *gb_command_gaction_provider_new (IdeWorkbench *workbench);
+GbpCommandBarSuggestion *gbp_command_bar_suggestion_new (IdeCommand *command);
+IdeCommand *gbp_command_bar_suggestion_get_command (GbpCommandBarSuggestion *self);
G_END_DECLS
diff --git a/src/plugins/command-bar/gbp-command-bar-workspace-addin.c
b/src/plugins/command-bar/gbp-command-bar-workspace-addin.c
new file mode 100644
index 000000000..fb9ca10f4
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar-workspace-addin.c
@@ -0,0 +1,165 @@
+/* gbp-command-bar-workspace-addin.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-command-bar-workspace-addin"
+
+#include "config.h"
+
+#include <libide-editor.h>
+#include <libide-gui.h>
+#include <libide-terminal.h>
+
+#include "gbp-command-bar.h"
+#include "gbp-command-bar-workspace-addin.h"
+
+struct _GbpCommandBarWorkspaceAddin
+{
+ GObject parent_instance;
+ GbpCommandBar *command_bar;
+};
+
+static gboolean
+position_command_bar_cb (GbpCommandBarWorkspaceAddin *self,
+ GtkWidget *child,
+ GdkRectangle *area,
+ GtkOverlay *overlay)
+{
+ GtkRequisition min, nat;
+
+ g_assert (GBP_IS_COMMAND_BAR_WORKSPACE_ADDIN (self));
+ g_assert (GTK_IS_WIDGET (child));
+
+ if (!GBP_IS_COMMAND_BAR (child))
+ return FALSE;
+
+ gtk_widget_get_allocation (GTK_WIDGET (overlay), area);
+ gtk_widget_get_preferred_size (child, &min, &nat);
+
+ area->x = (area->width - nat.width) / 2;
+ area->y = 100;
+ area->width = nat.width;
+ area->height = nat.height;
+
+ return TRUE;
+}
+
+static void
+gbp_command_bar_workspace_addin_dismiss_command_bar (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpCommandBarWorkspaceAddin *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_COMMAND_BAR_WORKSPACE_ADDIN (self));
+
+ if (self->command_bar)
+ gbp_command_bar_dismiss (self->command_bar);
+}
+
+static void
+gbp_command_bar_workspace_addin_reveal_command_bar (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpCommandBarWorkspaceAddin *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_COMMAND_BAR_WORKSPACE_ADDIN (self));
+
+ if (self->command_bar)
+ gbp_command_bar_reveal (self->command_bar);
+}
+
+static const GActionEntry entries[] = {
+ { "dismiss-command-bar", gbp_command_bar_workspace_addin_dismiss_command_bar },
+ { "reveal-command-bar", gbp_command_bar_workspace_addin_reveal_command_bar },
+};
+
+static void
+gbp_command_bar_workspace_addin_load (IdeWorkspaceAddin *addin,
+ IdeWorkspace *workspace)
+{
+ GbpCommandBarWorkspaceAddin *self = (GbpCommandBarWorkspaceAddin *)addin;
+ GtkOverlay *overlay;
+
+ g_assert (IDE_IS_WORKSPACE_ADDIN (self));
+ g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace) ||
+ IDE_IS_EDITOR_WORKSPACE (workspace) ||
+ IDE_IS_TERMINAL_WORKSPACE (workspace));
+
+ self->command_bar = g_object_new (GBP_TYPE_COMMAND_BAR,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_END,
+ "visible", FALSE,
+ NULL);
+ overlay = ide_workspace_get_overlay (workspace);
+ g_signal_connect_object (overlay,
+ "get-child-position",
+ G_CALLBACK (position_command_bar_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ gtk_overlay_add_overlay (overlay, GTK_WIDGET (self->command_bar));
+
+ /* Add actions for shortcuts to activate */
+ g_action_map_add_action_entries (G_ACTION_MAP (workspace),
+ entries,
+ G_N_ELEMENTS (entries),
+ self);
+}
+
+static void
+gbp_command_bar_workspace_addin_unload (IdeWorkspaceAddin *addin,
+ IdeWorkspace *workspace)
+{
+ GbpCommandBarWorkspaceAddin *self = (GbpCommandBarWorkspaceAddin *)addin;
+
+ g_assert (IDE_IS_WORKSPACE_ADDIN (self));
+ g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace) ||
+ IDE_IS_EDITOR_WORKSPACE (workspace) ||
+ IDE_IS_TERMINAL_WORKSPACE (workspace));
+
+ /* Remove all the actions we added */
+ for (guint i = 0; i < G_N_ELEMENTS (entries); i++)
+ g_action_map_remove_action (G_ACTION_MAP (workspace), entries[i].name);
+
+ if (self->command_bar != NULL)
+ gtk_widget_destroy (GTK_WIDGET (self->command_bar));
+}
+
+static void
+workspace_addin_iface_init (IdeWorkspaceAddinInterface *iface)
+{
+ iface->load = gbp_command_bar_workspace_addin_load;
+ iface->unload = gbp_command_bar_workspace_addin_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpCommandBarWorkspaceAddin, gbp_command_bar_workspace_addin, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKSPACE_ADDIN, workspace_addin_iface_init))
+
+static void
+gbp_command_bar_workspace_addin_class_init (GbpCommandBarWorkspaceAddinClass *klass)
+{
+}
+
+static void
+gbp_command_bar_workspace_addin_init (GbpCommandBarWorkspaceAddin *self)
+{
+}
diff --git a/src/plugins/command-bar/gb-command-gaction.h
b/src/plugins/command-bar/gbp-command-bar-workspace-addin.h
similarity index 68%
rename from src/plugins/command-bar/gb-command-gaction.h
rename to src/plugins/command-bar/gbp-command-bar-workspace-addin.h
index a7bdab6d7..4a091259d 100644
--- a/src/plugins/command-bar/gb-command-gaction.h
+++ b/src/plugins/command-bar/gbp-command-bar-workspace-addin.h
@@ -1,6 +1,6 @@
-/* gb-command-gaction.h
+/* gbp-command-bar-workspace-addin.h
*
- * Copyright 2014-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
*
* 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
@@ -20,12 +20,12 @@
#pragma once
-#include "gb-command.h"
+#include <glib-object.h>
G_BEGIN_DECLS
-#define GB_TYPE_COMMAND_GACTION (gb_command_gaction_get_type())
+#define GBP_TYPE_COMMAND_BAR_WORKSPACE_ADDIN (gbp_command_bar_workspace_addin_get_type())
-G_DECLARE_FINAL_TYPE (GbCommandGaction, gb_command_gaction, GB, COMMAND_GACTION, GbCommand)
+G_DECLARE_FINAL_TYPE (GbpCommandBarWorkspaceAddin, gbp_command_bar_workspace_addin, GBP,
COMMAND_BAR_WORKSPACE_ADDIN, GObject)
G_END_DECLS
diff --git a/src/plugins/command-bar/gbp-command-bar.c b/src/plugins/command-bar/gbp-command-bar.c
new file mode 100644
index 000000000..a15d57cc7
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar.c
@@ -0,0 +1,294 @@
+/* gbp-command-bar.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-command-bar"
+
+#include "config.h"
+
+#include <libide-gui.h>
+
+#include "gbp-command-bar.h"
+#include "gbp-command-bar-model.h"
+#include "gbp-command-bar-private.h"
+#include "gbp-command-bar-suggestion.h"
+
+struct _GbpCommandBar
+{
+ DzlBin parent_instance;
+ DzlSuggestionEntry *entry;
+ GtkRevealer *revealer;
+};
+
+G_DEFINE_TYPE (GbpCommandBar, gbp_command_bar, DZL_TYPE_BIN)
+
+static void
+replace_model (GbpCommandBar *self,
+ GbpCommandBarModel *model)
+{
+ GListModel *old_model;
+
+ g_assert (GBP_IS_COMMAND_BAR (self));
+ g_assert (!model || GBP_IS_COMMAND_BAR_MODEL (model));
+
+ old_model = dzl_suggestion_entry_get_model (self->entry);
+ dzl_suggestion_entry_set_model (self->entry, G_LIST_MODEL (model));
+ if (old_model != NULL)
+ ide_object_destroy (IDE_OBJECT (old_model));
+}
+
+static void
+gbp_command_bar_complete_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpCommandBarModel *model = (GbpCommandBarModel *)object;
+ g_autoptr(GbpCommandBar) self = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (GBP_IS_COMMAND_BAR_MODEL (model));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (GBP_IS_COMMAND_BAR (self));
+
+ if (gbp_command_bar_model_complete_finish (model, result, &error))
+ replace_model (self, model);
+}
+
+static void
+gbp_command_bar_changed_cb (GbpCommandBar *self,
+ DzlSuggestionEntry *entry)
+{
+ g_autoptr(GbpCommandBarModel) model = NULL;
+ IdeWorkspace *workspace;
+ const gchar *text;
+ IdeContext *context;
+
+ g_assert (GBP_IS_COMMAND_BAR (self));
+ g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+ text = dzl_suggestion_entry_get_typed_text (entry);
+
+ if (!gtk_widget_has_focus (GTK_WIDGET (entry)) || ide_str_empty0 (text))
+ {
+ replace_model (self, NULL);
+ return;
+ }
+
+ g_debug ("Command Bar: %s", text);
+
+ context = ide_widget_get_context (GTK_WIDGET (self));
+ model = gbp_command_bar_model_new (context);
+ workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+
+ gbp_command_bar_model_complete_async (model,
+ workspace,
+ text,
+ NULL,
+ gbp_command_bar_complete_cb,
+ g_object_ref (self));
+}
+
+static gboolean
+gbp_command_bar_focus_out_event_cb (GbpCommandBar *self,
+ GdkEventFocus *focus,
+ DzlSuggestionEntry *entry)
+{
+ g_assert (GBP_IS_COMMAND_BAR (self));
+ g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+ if (gtk_revealer_get_reveal_child (self->revealer))
+ {
+ gtk_revealer_set_reveal_child (self->revealer, FALSE);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ }
+
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
+gbp_command_bar_child_revealed_cb (GbpCommandBar *self,
+ GParamSpec *pspec,
+ GtkRevealer *revealer)
+{
+ g_assert (GBP_IS_COMMAND_BAR (self));
+ g_assert (GTK_IS_REVEALER (revealer));
+
+ if (gtk_revealer_get_child_revealed (revealer))
+ {
+ if (!gtk_widget_has_focus (GTK_WIDGET (self->entry)))
+ gtk_widget_grab_focus (GTK_WIDGET (self->entry));
+ }
+ else
+ gtk_widget_hide (GTK_WIDGET (self));
+}
+
+static void
+gbp_command_bar_activate_suggestion_cb (GbpCommandBar *self,
+ DzlSuggestionEntry *entry)
+{
+ DzlSuggestion *suggestion;
+
+ g_assert (GBP_IS_COMMAND_BAR (self));
+ g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+ if ((suggestion = dzl_suggestion_entry_get_suggestion (entry)))
+ {
+ GbpCommandBarSuggestion *cbs = GBP_COMMAND_BAR_SUGGESTION (suggestion);
+ IdeCommand *command = gbp_command_bar_suggestion_get_command (cbs);
+
+ ide_command_run_async (command, NULL, NULL, NULL);
+ }
+}
+
+static void
+gbp_command_bar_hide_suggestions_cb (GbpCommandBar *self,
+ DzlSuggestionEntry *entry)
+{
+ g_assert (GBP_IS_COMMAND_BAR (self));
+ g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+
+ if (gtk_widget_has_focus (GTK_WIDGET (entry)))
+ gbp_command_bar_dismiss (self);
+}
+
+static void
+position_popover_cb (DzlSuggestionEntry *entry,
+ GdkRectangle *area,
+ gboolean *is_absolute,
+ gpointer user_data)
+{
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (DZL_IS_SUGGESTION_ENTRY (entry));
+ g_assert (area != NULL);
+ g_assert (is_absolute != NULL);
+
+ dzl_suggestion_entry_default_position_func (entry, area, is_absolute, NULL);
+
+ /* We want to slightly adjust the popover positioning so it looks like the
+ * popover disappears into the entry. It makes the revealer out a bit less
+ * jarring as we hide the entry/window.
+ */
+ area->x += 3;
+ area->width -= 6;
+ area->y += 3;
+}
+
+static void
+gbp_command_bar_class_init (GbpCommandBarClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_css_name (widget_class, "commandbar");
+ gtk_widget_class_set_template_from_resource (widget_class, "/plugins/command-bar/gbp-command-bar.ui");
+ gtk_widget_class_bind_template_child (widget_class, GbpCommandBar, entry);
+ gtk_widget_class_bind_template_child (widget_class, GbpCommandBar, revealer);
+}
+
+static void
+gbp_command_bar_init (GbpCommandBar *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ gtk_widget_set_can_focus (GTK_WIDGET (self), FALSE);
+
+ g_signal_connect_object (self->revealer,
+ "notify::child-revealed",
+ G_CALLBACK (gbp_command_bar_child_revealed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (self->entry,
+ "activate-suggestion",
+ G_CALLBACK (gbp_command_bar_activate_suggestion_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (self->entry,
+ "hide-suggestions",
+ G_CALLBACK (gbp_command_bar_hide_suggestions_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (self->entry,
+ "focus-out-event",
+ G_CALLBACK (gbp_command_bar_focus_out_event_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (self->entry,
+ "changed",
+ G_CALLBACK (gbp_command_bar_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ dzl_suggestion_entry_set_position_func (self->entry,
+ position_popover_cb,
+ NULL,
+ NULL);
+
+ _gbp_command_bar_init_shortcuts (self);
+}
+
+void
+gbp_command_bar_reveal (GbpCommandBar *self)
+{
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (GBP_IS_COMMAND_BAR (self));
+
+ if (!gtk_widget_get_visible (GTK_WIDGET (self)))
+ {
+ /* First clear reveal child so that we will fade in properly
+ * when setting reveal child below.
+ */
+ gtk_revealer_set_reveal_child (self->revealer, FALSE);
+ gtk_widget_show (GTK_WIDGET (self));
+ }
+
+ gtk_revealer_set_reveal_child (self->revealer, TRUE);
+
+ /* We need to try to grab focus immediately (best effort) or there is
+ * potential for input events to be delivered to the previously focused
+ * widget. We can't do this until after setting reveal-child or we can
+ * get warnings about the widget not being ready for events.
+ */
+ gtk_widget_grab_focus (GTK_WIDGET (self->entry));
+}
+
+void
+gbp_command_bar_dismiss (GbpCommandBar *self)
+{
+ IdeWorkspace *workspace;
+ IdeSurface *surface;
+ IdePage *page;
+
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (GBP_IS_COMMAND_BAR (self));
+
+ gtk_revealer_set_reveal_child (self->revealer, FALSE);
+ workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+ surface = ide_workspace_get_visible_surface (workspace);
+ page = ide_workspace_get_most_recent_page (workspace);
+
+ if (page != NULL)
+ gtk_widget_grab_focus (GTK_WIDGET (page));
+ else
+ gtk_widget_child_focus (GTK_WIDGET (surface), GTK_DIR_TAB_FORWARD);
+
+ gtk_entry_set_text (GTK_ENTRY (self->entry), "");
+}
diff --git a/src/plugins/command-bar/gb-command-bar.h b/src/plugins/command-bar/gbp-command-bar.h
similarity index 67%
rename from src/plugins/command-bar/gb-command-bar.h
rename to src/plugins/command-bar/gbp-command-bar.h
index a13a9dfaa..cecff6166 100644
--- a/src/plugins/command-bar/gb-command-bar.h
+++ b/src/plugins/command-bar/gbp-command-bar.h
@@ -1,6 +1,6 @@
-/* gb-command-bar.h
+/* gbp-command-bar.h
*
- * Copyright 2014-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
*
* 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
@@ -20,16 +20,16 @@
#pragma once
+#include <dazzle.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
-#define GB_TYPE_COMMAND_BAR (gb_command_bar_get_type())
+#define GBP_TYPE_COMMAND_BAR (gbp_command_bar_get_type())
-G_DECLARE_FINAL_TYPE (GbCommandBar, gb_command_bar, GB, COMMAND_BAR, GtkRevealer)
+G_DECLARE_FINAL_TYPE (GbpCommandBar, gbp_command_bar, GBP, COMMAND_BAR, DzlBin)
-GtkWidget *gb_command_bar_new (void);
-void gb_command_bar_show (GbCommandBar *bar);
-void gb_command_bar_hide (GbCommandBar *bar);
+void gbp_command_bar_dismiss (GbpCommandBar *self);
+void gbp_command_bar_reveal (GbpCommandBar *self);
G_END_DECLS
diff --git a/src/plugins/command-bar/gbp-command-bar.ui b/src/plugins/command-bar/gbp-command-bar.ui
new file mode 100644
index 000000000..49791b93f
--- /dev/null
+++ b/src/plugins/command-bar/gbp-command-bar.ui
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GbpCommandBar" parent="DzlBin">
+ <child>
+ <object class="GtkRevealer" id="revealer">
+ <property name="reveal-child">false</property>
+ <property name="transition-type">crossfade</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="DzlSuggestionEntry" id="entry">
+ <property name="width-chars">45</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/plugins/command-bar/gbp-gaction-command.c b/src/plugins/command-bar/gbp-gaction-command.c
new file mode 100644
index 000000000..9ffbf7dfa
--- /dev/null
+++ b/src/plugins/command-bar/gbp-gaction-command.c
@@ -0,0 +1,160 @@
+/* gbp-gaction-command.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-gaction-command"
+
+#include "config.h"
+
+#include "gbp-gaction-command.h"
+
+struct _GbpGactionCommand
+{
+ IdeObject parent_instance;
+ GtkWidget *widget;
+ gchar *group;
+ gchar *name;
+ GVariant *param;
+ gchar *title;
+ guint priority;
+};
+
+static void
+gbp_gaction_command_run_async (IdeCommand *command,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GbpGactionCommand *self = (GbpGactionCommand *)command;
+ g_autoptr(IdeTask) task = NULL;
+
+ g_assert (GBP_IS_GACTION_COMMAND (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_gaction_command_run_async);
+
+ if (self->widget != NULL)
+ dzl_gtk_widget_action (self->widget, self->group, self->name, self->param);
+
+ ide_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+gbp_gaction_command_run_finish (IdeCommand *command,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (GBP_IS_GACTION_COMMAND (command));
+ g_assert (IDE_IS_TASK (result));
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
+
+static gchar *
+gbp_gaction_command_get_title (IdeCommand *command)
+{
+ GbpGactionCommand *self = (GbpGactionCommand *)command;
+
+ g_assert (GBP_IS_GACTION_COMMAND (self));
+
+ return g_strdup (self->title);
+}
+
+static void
+command_iface_init (IdeCommandInterface *iface)
+{
+ iface->run_async = gbp_gaction_command_run_async;
+ iface->run_finish = gbp_gaction_command_run_finish;
+ iface->get_title = gbp_gaction_command_get_title;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpGactionCommand, gbp_gaction_command, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_COMMAND, command_iface_init))
+
+static void
+gbp_gaction_command_finalize (GObject *object)
+{
+ GbpGactionCommand *self = (GbpGactionCommand *)object;
+
+ g_clear_pointer (&self->group, g_free);
+ g_clear_pointer (&self->name, g_free);
+ g_clear_pointer (&self->param, g_variant_unref);
+ g_clear_pointer (&self->title, g_free);
+
+ if (self->widget != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (self->widget,
+ G_CALLBACK (gtk_widget_destroyed),
+ &self->widget);
+ self->widget = NULL;
+ }
+
+ G_OBJECT_CLASS (gbp_gaction_command_parent_class)->finalize (object);
+}
+
+static void
+gbp_gaction_command_class_init (GbpGactionCommandClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gbp_gaction_command_finalize;
+}
+
+static void
+gbp_gaction_command_init (GbpGactionCommand *self)
+{
+}
+
+GbpGactionCommand *
+gbp_gaction_command_new (GtkWidget *widget,
+ const gchar *group,
+ const gchar *name,
+ GVariant *param,
+ const gchar *title,
+ guint priority)
+{
+ GbpGactionCommand *self;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (group != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ self = g_object_new (GBP_TYPE_GACTION_COMMAND, NULL);
+ self->widget = widget;
+ self->group = g_strdup (group);
+ self->name = g_strdup (name);
+ self->param = param ? g_variant_ref_sink (param) : NULL;
+ self->title = g_strdup (title);
+ self->priority = priority;
+
+ g_signal_connect (self->widget,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &self->widget);
+
+ return g_steal_pointer (&self);
+}
+
+gint
+gbp_gaction_command_compare (GbpGactionCommand *a,
+ GbpGactionCommand *b)
+{
+ return (gint)a->priority - (gint)b->priority;
+}
diff --git a/src/plugins/command-bar/gbp-gaction-command.h b/src/plugins/command-bar/gbp-gaction-command.h
new file mode 100644
index 000000000..13cf7a7e3
--- /dev/null
+++ b/src/plugins/command-bar/gbp-gaction-command.h
@@ -0,0 +1,40 @@
+/* gbp-gaction-command.h
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-gui.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_GACTION_COMMAND (gbp_gaction_command_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpGactionCommand, gbp_gaction_command, GBP, GACTION_COMMAND, IdeObject)
+
+gint gbp_gaction_command_compare (GbpGactionCommand *a,
+ GbpGactionCommand *b);
+GbpGactionCommand *gbp_gaction_command_new (GtkWidget *widget,
+ const gchar *group,
+ const gchar *name,
+ GVariant *param,
+ const gchar *title,
+ guint priority);
+
+G_END_DECLS
diff --git a/src/plugins/command-bar/meson.build b/src/plugins/command-bar/meson.build
index 139844f76..76bde4928 100644
--- a/src/plugins/command-bar/meson.build
+++ b/src/plugins/command-bar/meson.build
@@ -1,35 +1,18 @@
-if get_option('with_command_bar')
+plugins_sources += files([
+ 'command-bar-plugin.c',
+ 'gbp-command-bar.c',
+ 'gbp-command-bar-command-provider.c',
+ 'gbp-command-bar-model.c',
+ 'gbp-command-bar-shortcuts.c',
+ 'gbp-command-bar-suggestion.c',
+ 'gbp-command-bar-workspace-addin.c',
+ 'gbp-gaction-command.c',
+])
-command_bar_resources = gnome.compile_resources(
- 'gb-command-bar-resources',
- 'gb-command-bar.gresource.xml',
- c_name: 'gb_command_bar',
+plugin_command_bar_resources = gnome.compile_resources(
+ 'gbp-command-bar-resources',
+ 'command-bar.gresource.xml',
+ c_name: 'gbp_command_bar',
)
-command_bar_sources = [
- 'gb-command-bar.c',
- 'gb-command-bar.h',
- 'gb-command-gaction-provider.c',
- 'gb-command-gaction-provider.h',
- 'gb-command-gaction.c',
- 'gb-command-gaction.h',
- 'gb-command-manager.c',
- 'gb-command-manager.h',
- 'gb-command-provider.c',
- 'gb-command-provider.h',
- 'gb-command-result.c',
- 'gb-command-result.h',
- 'gb-command-vim-provider.c',
- 'gb-command-vim-provider.h',
- 'gb-command-vim.c',
- 'gb-command-vim.h',
- 'gb-command.c',
- 'gb-command.h',
- 'gb-vim.c',
- 'gb-vim.h',
-]
-
-gnome_builder_plugins_sources += files(command_bar_sources)
-gnome_builder_plugins_sources += command_bar_resources[0]
-
-endif
+plugins_sources += plugin_command_bar_resources[0]
diff --git a/src/plugins/command-bar/themes/shared.css b/src/plugins/command-bar/themes/shared.css
index 22f302a4b..4e66a47de 100644
--- a/src/plugins/command-bar/themes/shared.css
+++ b/src/plugins/command-bar/themes/shared.css
@@ -1,32 +1,5 @@
-commandbar > box.vertical > box.horizontal {
- border: none;
- box-shadow: 0px 10px 5px -10px shade(@theme_selected_bg_color, 0.3) inset;
- color: @theme_selected_fg_color;
- background-color: @theme_selected_bg_color;
- background-size: 8px 8px;
- background-image: repeating-linear-gradient(0deg, alpha(@theme_selected_fg_color,0.05),
alpha(@theme_selected_fg_color,0.05) 1px, transparent 1px, transparent 8px),
- repeating-linear-gradient(-90deg, alpha(@theme_selected_fg_color,0.05),
alpha(@theme_selected_fg_color,0.05) 1px, transparent 1px, transparent 8px);
-}
commandbar entry {
- font-family: Monospace;
- background-image: none;
- background-color: transparent;
- min-height: 0px;
- color: @theme_selected_fg_color;
- border: none;
- padding: 6px;
- caret-color: @theme_selected_fg_color;
- box-shadow: none;
-}
-commandbar flowbox {
- opacity: 0.9;
- padding: 12px;
- color: @theme_selected_fg_color;
- background: transparent;
-}
-commandbar viewport {
- background-color: @theme_selected_bg_color;
- background-size: 8px 8px;
- background-image: repeating-linear-gradient(0deg, alpha(@theme_selected_fg_color,0.05),
alpha(@theme_selected_fg_color,0.05) 1px, transparent 1px, transparent 8px),
- repeating-linear-gradient(-90deg, alpha(@theme_selected_fg_color,0.05),
alpha(@theme_selected_fg_color,0.05) 1px, transparent 1px, transparent 8px);
+ margin: 10px;
+ border-width: 3px;
+ box-shadow: 0 0 5px @wm_shadow;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]