[gnome-builder/wip/chergert/shortcut-editing: 2/2] plugins/shortcutui: start on tweaks for shortcut editing
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/shortcut-editing: 2/2] plugins/shortcutui: start on tweaks for shortcut editing
- Date: Tue, 4 Oct 2022 00:09:38 +0000 (UTC)
commit e257335d9c7fd1275c3858fb6fc8fbb45935737a
Author: Christian Hergert <chergert redhat com>
Date: Mon Oct 3 17:09:24 2022 -0700
plugins/shortcutui: start on tweaks for shortcut editing
src/plugins/meson.build | 1 +
.../shortcutui/gbp-shortcutui-action-model.c | 144 ++++++++++
.../shortcutui/gbp-shortcutui-action-model.h | 33 +++
src/plugins/shortcutui/gbp-shortcutui-action.c | 303 +++++++++++++++++++++
src/plugins/shortcutui/gbp-shortcutui-action.h | 38 +++
src/plugins/shortcutui/gbp-shortcutui-dialog.c | 157 +++++++++++
src/plugins/shortcutui/gbp-shortcutui-dialog.h | 31 +++
src/plugins/shortcutui/gbp-shortcutui-dialog.ui | 89 ++++++
src/plugins/shortcutui/gbp-shortcutui-row.c | 186 +++++++++++++
src/plugins/shortcutui/gbp-shortcutui-row.h | 34 +++
src/plugins/shortcutui/gbp-shortcutui-row.ui | 8 +
.../shortcutui/gbp-shortcutui-tweaks-addin.c | 125 +++++++++
.../shortcutui/gbp-shortcutui-tweaks-addin.h | 31 +++
src/plugins/shortcutui/meson.build | 16 ++
src/plugins/shortcutui/shortcutui-plugin.c | 38 +++
src/plugins/shortcutui/shortcutui.gresource.xml | 10 +
src/plugins/shortcutui/shortcutui.plugin | 9 +
src/plugins/shortcutui/style.css | 8 +
src/plugins/shortcutui/tweaks.ui | 25 ++
19 files changed, 1286 insertions(+)
---
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index deb2d81fe..058675856 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -117,6 +117,7 @@ subdir('rust-analyzer')
subdir('sdkui')
subdir('sessionui')
subdir('shellcmd')
+subdir('shortcutui')
subdir('snippets')
subdir('spellcheck')
subdir('sphinx-preview')
diff --git a/src/plugins/shortcutui/gbp-shortcutui-action-model.c
b/src/plugins/shortcutui/gbp-shortcutui-action-model.c
new file mode 100644
index 000000000..072fd7816
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-action-model.c
@@ -0,0 +1,144 @@
+/* gbp-shortcutui-action-model.c
+ *
+ * Copyright 2022 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-shortcutui-action-model"
+
+#include "config.h"
+
+#include <libide-gui.h>
+
+#include "ide-application-private.h"
+
+#include "gbp-shortcutui-action.h"
+#include "gbp-shortcutui-action-model.h"
+
+struct _GbpShortcutuiActionModel
+{
+ GObject parent_instance;
+ GPtrArray *items;
+};
+
+static guint
+gbp_shortcutui_action_model_get_n_items (GListModel *model)
+{
+ return GBP_SHORTCUTUI_ACTION_MODEL (model)->items->len;
+}
+
+static GType
+gbp_shortcutui_action_model_get_item_type (GListModel *model)
+{
+ return GBP_TYPE_SHORTCUTUI_ACTION;
+}
+
+static gpointer
+gbp_shortcutui_action_model_get_item (GListModel *model,
+ guint position)
+{
+ GPtrArray *items = GBP_SHORTCUTUI_ACTION_MODEL (model)->items;
+
+ if (position < items->len)
+ return g_object_ref (g_ptr_array_index (items, position));
+
+ return NULL;
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+ iface->get_n_items = gbp_shortcutui_action_model_get_n_items;
+ iface->get_item = gbp_shortcutui_action_model_get_item;
+ iface->get_item_type = gbp_shortcutui_action_model_get_item_type;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpShortcutuiActionModel, gbp_shortcutui_action_model, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
+
+static int
+sort_actions (gconstpointer a,
+ gconstpointer b)
+{
+ const GbpShortcutuiAction * const *aptr = a;
+ const GbpShortcutuiAction * const *bptr = b;
+
+ return gbp_shortcutui_action_compare (*aptr, *bptr);
+}
+
+static void
+populate_shortcut_info_cb (const IdeShortcutInfo *info,
+ gpointer user_data)
+{
+ GPtrArray *items = user_data;
+
+ g_assert (info != NULL);
+ g_assert (items != NULL);
+
+ g_ptr_array_add (items,
+ g_object_new (GBP_TYPE_SHORTCUTUI_ACTION,
+ "action-name", ide_shortcut_info_get_action_name (info),
+ "action-target", ide_shortcut_info_get_action_target (info),
+ "title", ide_shortcut_info_get_title (info),
+ "subtitle", ide_shortcut_info_get_subtitle (info),
+ "page", ide_shortcut_info_get_page (info),
+ "group", ide_shortcut_info_get_group (info),
+ NULL));
+}
+
+static void
+gbp_shortcutui_action_model_constructed (GObject *object)
+{
+ GbpShortcutuiActionModel *self = (GbpShortcutuiActionModel *)object;
+
+ G_OBJECT_CLASS (gbp_shortcutui_action_model_parent_class)->constructed (object);
+
+ ide_shortcut_info_foreach (populate_shortcut_info_cb, self->items);
+
+ g_ptr_array_sort (self->items, sort_actions);
+}
+
+static void
+gbp_shortcutui_action_model_dispose (GObject *object)
+{
+ GbpShortcutuiActionModel *self = (GbpShortcutuiActionModel *)object;
+
+ g_clear_pointer (&self->items, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (gbp_shortcutui_action_model_parent_class)->dispose (object);
+}
+
+static void
+gbp_shortcutui_action_model_class_init (GbpShortcutuiActionModelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gbp_shortcutui_action_model_constructed;
+ object_class->dispose = gbp_shortcutui_action_model_dispose;
+}
+
+static void
+gbp_shortcutui_action_model_init (GbpShortcutuiActionModel *self)
+{
+ self->items = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+GListModel *
+gbp_shortcutui_action_model_new (void)
+{
+ return g_object_new (GBP_TYPE_SHORTCUTUI_ACTION_MODEL, NULL);
+}
diff --git a/src/plugins/shortcutui/gbp-shortcutui-action-model.h
b/src/plugins/shortcutui/gbp-shortcutui-action-model.h
new file mode 100644
index 000000000..91f004869
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-action-model.h
@@ -0,0 +1,33 @@
+/* gbp-shortcutui-action-model.h
+ *
+ * Copyright 2022 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 <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SHORTCUTUI_ACTION_MODEL (gbp_shortcutui_action_model_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpShortcutuiActionModel, gbp_shortcutui_action_model, GBP, SHORTCUTUI_ACTION_MODEL,
GObject)
+
+GListModel *gbp_shortcutui_action_model_new (void);
+
+G_END_DECLS
diff --git a/src/plugins/shortcutui/gbp-shortcutui-action.c b/src/plugins/shortcutui/gbp-shortcutui-action.c
new file mode 100644
index 000000000..89d3dfc87
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-action.c
@@ -0,0 +1,303 @@
+/* gbp-shortcutui-action.c
+ *
+ * Copyright 2022 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-shortcutui-action"
+
+#include "config.h"
+
+#include "gbp-shortcutui-action.h"
+
+struct _GbpShortcutuiAction
+{
+ GObject parent_instance;
+
+ char *accelerator;
+ char *action_name;
+ char *group;
+ char *page;
+ char *search_text;
+ char *subtitle;
+ char *title;
+
+ GVariant *action_target;
+};
+
+enum {
+ PROP_0,
+ PROP_ACCELERATOR,
+ PROP_ACTION_NAME,
+ PROP_ACTION_TARGET,
+ PROP_SUBTITLE,
+ PROP_TITLE,
+ PROP_GROUP,
+ PROP_PAGE,
+ PROP_SEARCH_TEXT,
+ N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (GbpShortcutuiAction, gbp_shortcutui_action, G_TYPE_OBJECT)
+
+static GParamSpec *properties [N_PROPS];
+
+static const char *
+gbp_shortcutui_action_get_search_text (GbpShortcutuiAction *self)
+{
+ g_assert (GBP_IS_SHORTCUTUI_ACTION (self));
+
+ if (self->search_text == NULL)
+ {
+ GString *str = g_string_new (NULL);
+
+ if (self->page != NULL)
+ g_string_append_printf (str, "%s ", self->page);
+
+ if (self->group != NULL)
+ g_string_append_printf (str, "%s ", self->group);
+
+ if (self->title != NULL)
+ g_string_append_printf (str, "%s ", self->title);
+
+ if (self->subtitle != NULL)
+ g_string_append_printf (str, "%s ", self->subtitle);
+
+ self->search_text = g_string_free (str, FALSE);
+ }
+
+ return self->search_text;
+}
+
+static void
+gbp_shortcutui_action_dispose (GObject *object)
+{
+ GbpShortcutuiAction *self = (GbpShortcutuiAction *)object;
+
+ g_clear_pointer (&self->accelerator, g_free);
+ g_clear_pointer (&self->action_name, g_free);
+ g_clear_pointer (&self->action_target, g_variant_unref);
+ g_clear_pointer (&self->group, g_free);
+ g_clear_pointer (&self->page, g_free);
+ g_clear_pointer (&self->subtitle, g_free);
+ g_clear_pointer (&self->search_text, g_free);
+ g_clear_pointer (&self->title, g_free);
+
+ G_OBJECT_CLASS (gbp_shortcutui_action_parent_class)->dispose (object);
+}
+
+static void
+gbp_shortcutui_action_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpShortcutuiAction *self = GBP_SHORTCUTUI_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACCELERATOR:
+ g_value_set_string (value, self->accelerator);
+ break;
+
+ case PROP_ACTION_NAME:
+ g_value_set_string (value, self->action_name);
+ break;
+
+ case PROP_ACTION_TARGET:
+ g_value_set_variant (value, self->action_target);
+ break;
+
+ case PROP_SUBTITLE:
+ g_value_set_string (value, self->subtitle);
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, self->title);
+ break;
+
+ case PROP_GROUP:
+ g_value_set_string (value, self->group);
+ break;
+
+ case PROP_PAGE:
+ g_value_set_string (value, self->page);
+ break;
+
+ case PROP_SEARCH_TEXT:
+ g_value_set_string (value, gbp_shortcutui_action_get_search_text (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_shortcutui_action_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbpShortcutuiAction *self = GBP_SHORTCUTUI_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACCELERATOR:
+ self->accelerator = g_value_dup_string (value);
+ break;
+
+ case PROP_ACTION_NAME:
+ self->action_name = g_value_dup_string (value);
+ break;
+
+ case PROP_ACTION_TARGET:
+ self->action_target = g_value_dup_variant (value);
+ break;
+
+ case PROP_SUBTITLE:
+ self->subtitle = g_value_dup_string (value);
+ break;
+
+ case PROP_TITLE:
+ self->title = g_value_dup_string (value);
+ break;
+
+ case PROP_GROUP:
+ self->group = g_value_dup_string (value);
+ break;
+
+ case PROP_PAGE:
+ self->page = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_shortcutui_action_class_init (GbpShortcutuiActionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gbp_shortcutui_action_dispose;
+ object_class->get_property = gbp_shortcutui_action_get_property;
+ object_class->set_property = gbp_shortcutui_action_set_property;
+
+ properties [PROP_ACCELERATOR] =
+ g_param_spec_string ("accelerator", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_ACTION_NAME] =
+ g_param_spec_string ("action-name", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_ACTION_TARGET] =
+ g_param_spec_variant ("action-target", NULL, NULL,
+ G_VARIANT_TYPE_ANY,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_TITLE] =
+ g_param_spec_string ("title", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_SUBTITLE] =
+ g_param_spec_string ("subtitle", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_GROUP] =
+ g_param_spec_string ("group", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_PAGE] =
+ g_param_spec_string ("page", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_SEARCH_TEXT] =
+ g_param_spec_string ("search-text", NULL, NULL,
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_shortcutui_action_init (GbpShortcutuiAction *self)
+{
+}
+
+static inline int
+utf8_collate0 (const char *a,
+ const char *b)
+{
+ if (a == b)
+ return 0;
+
+ if (a == NULL)
+ return 1;
+
+ if (b == NULL)
+ return -1;
+
+ return g_utf8_collate (a, b);
+}
+
+int
+gbp_shortcutui_action_compare (const GbpShortcutuiAction *a,
+ const GbpShortcutuiAction *b)
+{
+ int ret;
+
+ if ((ret = utf8_collate0 (a->page, b->page)))
+ return ret;
+
+ if ((ret = utf8_collate0 (a->group, b->group)))
+ return ret;
+
+ if ((ret = utf8_collate0 (a->title, b->title)))
+ return ret;
+
+ return 0;
+}
+
+gboolean
+gbp_shortcutui_action_is_same_group (const GbpShortcutuiAction *a,
+ const GbpShortcutuiAction *b)
+{
+ return utf8_collate0 (a->page, b->page) == 0 &&
+ utf8_collate0 (a->group, b->group) == 0;
+}
+
+const char *
+gbp_shortcutui_action_get_page (const GbpShortcutuiAction *self)
+{
+ return self->page;
+}
+
+const char *
+gbp_shortcutui_action_get_group (const GbpShortcutuiAction *self)
+{
+ return self->group;
+}
diff --git a/src/plugins/shortcutui/gbp-shortcutui-action.h b/src/plugins/shortcutui/gbp-shortcutui-action.h
new file mode 100644
index 000000000..9f3e08f8e
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-action.h
@@ -0,0 +1,38 @@
+/* gbp-shortcutui-action.h
+ *
+ * Copyright 2022 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 <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SHORTCUTUI_ACTION (gbp_shortcutui_action_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpShortcutuiAction, gbp_shortcutui_action, GBP, SHORTCUTUI_ACTION, GObject)
+
+const char *gbp_shortcutui_action_get_page (const GbpShortcutuiAction *self);
+const char *gbp_shortcutui_action_get_group (const GbpShortcutuiAction *self);
+int gbp_shortcutui_action_compare (const GbpShortcutuiAction *a,
+ const GbpShortcutuiAction *b);
+gboolean gbp_shortcutui_action_is_same_group (const GbpShortcutuiAction *a,
+ const GbpShortcutuiAction *b);
+
+G_END_DECLS
diff --git a/src/plugins/shortcutui/gbp-shortcutui-dialog.c b/src/plugins/shortcutui/gbp-shortcutui-dialog.c
new file mode 100644
index 000000000..e3fe162b3
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-dialog.c
@@ -0,0 +1,157 @@
+/* gbp-shortcutui-dialog.c
+ *
+ * Copyright 2022 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-shortcutui-dialog"
+
+#include "config.h"
+
+#include <libide-gui.h>
+
+#include "gbp-shortcutui-action.h"
+#include "gbp-shortcutui-action-model.h"
+#include "gbp-shortcutui-dialog.h"
+#include "gbp-shortcutui-row.h"
+
+struct _GbpShortcutuiDialog
+{
+ GtkWindow parent_instance;
+ GtkSearchEntry *search;
+ GtkListBox *results_list_box;
+ AdwPreferencesPage *overview;
+ AdwPreferencesPage *results;
+ AdwPreferencesPage *empty;
+ GtkStringFilter *string_filter;
+ GtkFilterListModel *filter_model;
+ guint update_source;
+};
+
+G_DEFINE_FINAL_TYPE (GbpShortcutuiDialog, gbp_shortcutui_dialog, GTK_TYPE_WINDOW)
+
+static void
+gbp_shortcutui_dialog_update_header_cb (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ g_assert (GBP_IS_SHORTCUTUI_ROW (row));
+ g_assert (!before || GBP_IS_SHORTCUTUI_ROW (before));
+
+ gbp_shortcutui_row_update_header (GBP_SHORTCUTUI_ROW (row),
+ GBP_SHORTCUTUI_ROW (before));
+}
+
+static GtkWidget *
+gbp_shortcutui_dialog_create_row_cb (gpointer item,
+ gpointer user_data)
+{
+ GbpShortcutuiAction *action = item;
+
+ g_assert (GBP_IS_SHORTCUTUI_ACTION (action));
+
+ return g_object_new (GBP_TYPE_SHORTCUTUI_ROW,
+ "action", action,
+ NULL);
+}
+
+static gboolean
+gbp_shortcutui_dialog_update_visible (gpointer user_data)
+{
+ GbpShortcutuiDialog *self = user_data;
+ const char *text;
+ guint n_items;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_SHORTCUTUI_DIALOG (self));
+
+ self->update_source = 0;
+
+ text = gtk_editable_get_text (GTK_EDITABLE (self->search));
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (self->filter_model));
+
+ if (ide_str_empty0 (text))
+ {
+ gtk_widget_show (GTK_WIDGET (self->overview));
+ gtk_widget_hide (GTK_WIDGET (self->results));
+ gtk_widget_hide (GTK_WIDGET (self->empty));
+ }
+ else
+ {
+ gboolean has_results = n_items > 0;
+
+ gtk_widget_hide (GTK_WIDGET (self->overview));
+ gtk_widget_set_visible (GTK_WIDGET (self->results), has_results);
+ gtk_widget_set_visible (GTK_WIDGET (self->empty), !has_results);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+gbp_shortcutui_dialog_queue_update (GbpShortcutuiDialog *self)
+{
+ g_assert (GBP_IS_SHORTCUTUI_DIALOG (self));
+
+ if (self->update_source == 0)
+ self->update_source = g_timeout_add (250, gbp_shortcutui_dialog_update_visible, self);
+}
+
+static void
+gbp_shortcutui_dialog_dispose (GObject *object)
+{
+ GbpShortcutuiDialog *self = (GbpShortcutuiDialog *)object;
+
+ g_clear_handle_id (&self->update_source, g_source_remove);
+
+ G_OBJECT_CLASS (gbp_shortcutui_dialog_parent_class)->dispose (object);
+}
+
+static void
+gbp_shortcutui_dialog_class_init (GbpShortcutuiDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gbp_shortcutui_dialog_dispose;
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/plugins/shortcutui/gbp-shortcutui-dialog.ui");
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, empty);
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, filter_model);
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, overview);
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, results);
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, results_list_box);
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, search);
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiDialog, string_filter);
+ gtk_widget_class_bind_template_callback (widget_class, gbp_shortcutui_dialog_queue_update);
+
+ g_type_ensure (GBP_TYPE_SHORTCUTUI_ACTION_MODEL);
+}
+
+static void
+gbp_shortcutui_dialog_init (GbpShortcutuiDialog *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ gtk_list_box_set_header_func (self->results_list_box,
+ gbp_shortcutui_dialog_update_header_cb,
+ NULL, NULL);
+ gtk_list_box_bind_model (self->results_list_box,
+ G_LIST_MODEL (self->filter_model),
+ gbp_shortcutui_dialog_create_row_cb,
+ NULL, NULL);
+}
diff --git a/src/plugins/shortcutui/gbp-shortcutui-dialog.h b/src/plugins/shortcutui/gbp-shortcutui-dialog.h
new file mode 100644
index 000000000..ff5864b52
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-dialog.h
@@ -0,0 +1,31 @@
+/* gbp-shortcutui-dialog.h
+ *
+ * Copyright 2022 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 <adwaita.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SHORTCUTUI_DIALOG (gbp_shortcutui_dialog_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpShortcutuiDialog, gbp_shortcutui_dialog, GBP, SHORTCUTUI_DIALOG, GtkWindow)
+
+G_END_DECLS
diff --git a/src/plugins/shortcutui/gbp-shortcutui-dialog.ui b/src/plugins/shortcutui/gbp-shortcutui-dialog.ui
new file mode 100644
index 000000000..d5c4dec19
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-dialog.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GbpShortcutuiDialog" parent="GtkWindow">
+ <style>
+ <class name="shortcutui"/>
+ </style>
+ <child type="titlebar">
+ <object class="AdwHeaderBar">
+ <child type="start">
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Reset All…</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack">
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">primary</property>
+ <property name="child">
+ <object class="AdwPreferencesPage">
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkSearchEntry" id="search">
+ <property name="halign">center</property>
+ <property name="width-chars">30</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup" id="overview">
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup" id="results">
+ <property name="visible">false</property>
+ <child>
+ <object class="GtkListBox" id="results_list_box">
+ <style>
+ <class name="boxed-list"/>
+ <class name="search"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup" id="empty">
+ <property name="visible">false</property>
+ <child>
+ <object class="AdwStatusPage">
+ <property name="icon-name">edit-find-symbolic</property>
+ <property name="title" translatable="yes">No keyboard shortcut found</property>
+ <property name="description" translatable="yes">Try a different search</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkFilterListModel" id="filter_model">
+ <signal name="notify::n-items" handler="gbp_shortcutui_dialog_queue_update" swapped="true"
object="GbpShortcutuiDialog"/>
+ <property name="incremental">false</property>
+ <property name="model">
+ <object class="GbpShortcutuiActionModel" id="action_model"/>
+ </property>
+ <property name="filter">
+ <object class="GtkStringFilter" id="string_filter">
+ <signal name="notify::search" handler="gbp_shortcutui_dialog_queue_update" swapped="true"
object="GbpShortcutuiDialog"/>
+ <binding name="search">
+ <lookup name="text">search</lookup>
+ </binding>
+ <property name="ignore-case">true</property>
+ <property name="match-mode">substring</property>
+ <property name="expression">
+ <lookup name="search-text" type="GbpShortcutuiAction"/>
+ </property>
+ </object>
+ </property>
+ </object>
+</interface>
diff --git a/src/plugins/shortcutui/gbp-shortcutui-row.c b/src/plugins/shortcutui/gbp-shortcutui-row.c
new file mode 100644
index 000000000..5f9905b87
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-row.c
@@ -0,0 +1,186 @@
+/* gbp-shortcutui-row.c
+ *
+ * Copyright 2022 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-shortcutui-row"
+
+#include "config.h"
+
+#include <libide-gui.h>
+
+#include "gbp-shortcutui-action.h"
+#include "gbp-shortcutui-row.h"
+
+struct _GbpShortcutuiRow
+{
+ AdwActionRow parent_instance;
+ GbpShortcutuiAction *action;
+ GtkWidget *shortcut;
+};
+
+G_DEFINE_FINAL_TYPE (GbpShortcutuiRow, gbp_shortcutui_row, ADW_TYPE_ACTION_ROW)
+
+enum {
+ PROP_0,
+ PROP_ACTION,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_shortcutui_row_set_action (GbpShortcutuiRow *self,
+ GbpShortcutuiAction *action)
+{
+ g_auto(GValue) title = G_VALUE_INIT;
+ g_auto(GValue) subtitle = G_VALUE_INIT;
+ g_auto(GValue) accelerator = G_VALUE_INIT;
+
+ g_assert (GBP_IS_SHORTCUTUI_ROW (self));
+ g_assert (GBP_IS_SHORTCUTUI_ACTION (action));
+
+ g_set_object (&self->action, action);
+
+ g_value_init (&title, G_TYPE_STRING);
+ g_value_init (&subtitle, G_TYPE_STRING);
+ g_value_init (&accelerator, G_TYPE_STRING);
+
+ g_object_get_property (G_OBJECT (action), "title", &title);
+ g_object_get_property (G_OBJECT (action), "subtitle", &subtitle);
+ g_object_get_property (G_OBJECT (action), "accelerator", &accelerator);
+
+ g_object_set_property (G_OBJECT (self), "title", &title);
+ g_object_set_property (G_OBJECT (self), "subtitle", &subtitle);
+ g_object_get_property (G_OBJECT (self->shortcut), "accelerator", &accelerator);
+}
+
+static void
+gbp_shortcutui_row_dispose (GObject *object)
+{
+ GbpShortcutuiRow *self = (GbpShortcutuiRow *)object;
+
+ g_clear_object (&self->action);
+
+ G_OBJECT_CLASS (gbp_shortcutui_row_parent_class)->dispose (object);
+}
+
+static void
+gbp_shortcutui_row_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpShortcutuiRow *self = GBP_SHORTCUTUI_ROW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTION:
+ g_value_set_object (value, self->action);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_shortcutui_row_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbpShortcutuiRow *self = GBP_SHORTCUTUI_ROW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTION:
+ gbp_shortcutui_row_set_action (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_shortcutui_row_class_init (GbpShortcutuiRowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gbp_shortcutui_row_dispose;
+ object_class->get_property = gbp_shortcutui_row_get_property;
+ object_class->set_property = gbp_shortcutui_row_set_property;
+
+ properties [PROP_ACTION] =
+ g_param_spec_object ("action", NULL, NULL,
+ GBP_TYPE_SHORTCUTUI_ACTION,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/plugins/shortcutui/gbp-shortcutui-row.ui");
+ gtk_widget_class_bind_template_child (widget_class, GbpShortcutuiRow, shortcut);
+}
+
+static void
+gbp_shortcutui_row_init (GbpShortcutuiRow *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+void
+gbp_shortcutui_row_update_header (GbpShortcutuiRow *self,
+ GbpShortcutuiRow *before)
+{
+ GtkWidget *header = NULL;
+
+ g_return_if_fail (GBP_IS_SHORTCUTUI_ROW (self));
+ g_return_if_fail (!before || GBP_IS_SHORTCUTUI_ROW (before));
+
+ if (self->action == NULL)
+ return;
+
+ if (before == NULL ||
+ !gbp_shortcutui_action_is_same_group (self->action, before->action))
+ {
+ const char *page = gbp_shortcutui_action_get_page (self->action);
+ const char *group = gbp_shortcutui_action_get_group (self->action);
+
+ if (page != NULL && group != NULL)
+ {
+ g_autofree char *title = g_strdup_printf ("%s / %s", page, group);
+
+ header = g_object_new (GTK_TYPE_LABEL,
+ "css-classes", IDE_STRV_INIT ("heading"),
+ "halign", GTK_ALIGN_START,
+ "hexpand", TRUE,
+ "label", title,
+ "use-markup", TRUE,
+ NULL);
+ }
+ }
+
+ if (header)
+ gtk_widget_add_css_class (GTK_WIDGET (self), "has-header");
+ else
+ gtk_widget_remove_css_class (GTK_WIDGET (self), "has-header");
+
+ gtk_list_box_row_set_header (GTK_LIST_BOX_ROW (self), header);
+}
diff --git a/src/plugins/shortcutui/gbp-shortcutui-row.h b/src/plugins/shortcutui/gbp-shortcutui-row.h
new file mode 100644
index 000000000..5b58ce548
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-row.h
@@ -0,0 +1,34 @@
+/* gbp-shortcutui-row.h
+ *
+ * Copyright 2022 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 <adwaita.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SHORTCUTUI_ROW (gbp_shortcutui_row_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpShortcutuiRow, gbp_shortcutui_row, GBP, SHORTCUTUI_ROW, AdwActionRow)
+
+void gbp_shortcutui_row_update_header (GbpShortcutuiRow *self,
+ GbpShortcutuiRow *before);
+
+G_END_DECLS
diff --git a/src/plugins/shortcutui/gbp-shortcutui-row.ui b/src/plugins/shortcutui/gbp-shortcutui-row.ui
new file mode 100644
index 000000000..eab654768
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-row.ui
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GbpShortcutuiRow" parent="AdwActionRow">
+ <child type="suffix">
+ <object class="GtkShortcutLabel" id="shortcut"/>
+ </child>
+ </template>
+</interface>
diff --git a/src/plugins/shortcutui/gbp-shortcutui-tweaks-addin.c
b/src/plugins/shortcutui/gbp-shortcutui-tweaks-addin.c
new file mode 100644
index 000000000..d451b3c40
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-tweaks-addin.c
@@ -0,0 +1,125 @@
+/* gbp-shortcutui-tweaks-addin.c
+ *
+ * Copyright 2022 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-shortcutui-tweaks-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-gui.h>
+
+#include "gbp-shortcutui-dialog.h"
+#include "gbp-shortcutui-tweaks-addin.h"
+
+struct _GbpShortcutuiTweaksAddin
+{
+ IdeTweaksAddin parent_instance;
+};
+
+G_DEFINE_FINAL_TYPE (GbpShortcutuiTweaksAddin, gbp_shortcutui_tweaks_addin, IDE_TYPE_TWEAKS_ADDIN)
+
+static void
+gbp_shortcutui_tweaks_addin_row_activated_cb (GbpShortcutuiTweaksAddin *self,
+ AdwActionRow *row)
+{
+ GbpShortcutuiDialog *dialog;
+ GtkRoot *root;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_SHORTCUTUI_TWEAKS_ADDIN (self));
+ g_assert (ADW_IS_ACTION_ROW (row));
+
+ root = gtk_widget_get_root (GTK_WIDGET (row));
+ dialog = g_object_new (GBP_TYPE_SHORTCUTUI_DIALOG,
+ "default-width", 700,
+ "default-height", 500,
+ "title", _("Keyboard Shortcuts"),
+ "transient-for", root,
+ "modal", TRUE,
+ NULL);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ IDE_EXIT;
+}
+
+static GtkWidget *
+shortcutui_create_shortcuts_cb (GbpShortcutuiTweaksAddin *self,
+ IdeTweaksItem *instance,
+ IdeTweaksItem *original)
+{
+ AdwActionRow *row;
+ GtkImage *image;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_SHORTCUTUI_TWEAKS_ADDIN (self));
+ g_assert (IDE_IS_TWEAKS_ITEM (instance));
+ g_assert (IDE_IS_TWEAKS_ITEM (original));
+
+ row = g_object_new (ADW_TYPE_ACTION_ROW,
+ "activatable", TRUE,
+ "title", _("View and Customize Shortcuts…"),
+ NULL);
+ image = g_object_new (GTK_TYPE_IMAGE,
+ "icon-name", "go-next-symbolic",
+ NULL);
+ adw_action_row_add_suffix (row, GTK_WIDGET (image));
+
+ g_signal_connect_object (row,
+ "activated",
+ G_CALLBACK (gbp_shortcutui_tweaks_addin_row_activated_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ return GTK_WIDGET (row);
+}
+
+static void
+gbp_shortcutui_tweaks_addin_load (IdeTweaksAddin *addin,
+ IdeTweaks *tweaks)
+{
+ GbpShortcutuiTweaksAddin *self = (GbpShortcutuiTweaksAddin *)addin;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_SHORTCUTUI_TWEAKS_ADDIN (self));
+ g_assert (IDE_IS_TWEAKS (tweaks));
+
+ ide_tweaks_addin_set_resource_paths (IDE_TWEAKS_ADDIN (self),
+ IDE_STRV_INIT ("/plugins/shortcutui/tweaks.ui"));
+ ide_tweaks_addin_bind_callback (IDE_TWEAKS_ADDIN (self), shortcutui_create_shortcuts_cb);
+
+ IDE_TWEAKS_ADDIN_CLASS (gbp_shortcutui_tweaks_addin_parent_class)->load (addin, tweaks);
+}
+
+static void
+gbp_shortcutui_tweaks_addin_class_init (GbpShortcutuiTweaksAddinClass *klass)
+{
+ IdeTweaksAddinClass *tweaks_addin_class = IDE_TWEAKS_ADDIN_CLASS (klass);
+
+ tweaks_addin_class->load = gbp_shortcutui_tweaks_addin_load;
+}
+
+static void
+gbp_shortcutui_tweaks_addin_init (GbpShortcutuiTweaksAddin *self)
+{
+}
diff --git a/src/plugins/shortcutui/gbp-shortcutui-tweaks-addin.h
b/src/plugins/shortcutui/gbp-shortcutui-tweaks-addin.h
new file mode 100644
index 000000000..628145f5f
--- /dev/null
+++ b/src/plugins/shortcutui/gbp-shortcutui-tweaks-addin.h
@@ -0,0 +1,31 @@
+/* gbp-shortcutui-tweaks-addin.h
+ *
+ * Copyright 2022 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-tweaks.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SHORTCUTUI_TWEAKS_ADDIN (gbp_shortcutui_tweaks_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpShortcutuiTweaksAddin, gbp_shortcutui_tweaks_addin, GBP, SHORTCUTUI_TWEAKS_ADDIN,
IdeTweaksAddin)
+
+G_END_DECLS
diff --git a/src/plugins/shortcutui/meson.build b/src/plugins/shortcutui/meson.build
new file mode 100644
index 000000000..6aa30d82f
--- /dev/null
+++ b/src/plugins/shortcutui/meson.build
@@ -0,0 +1,16 @@
+plugins_sources += files([
+ 'shortcutui-plugin.c',
+ 'gbp-shortcutui-action.c',
+ 'gbp-shortcutui-action-model.c',
+ 'gbp-shortcutui-dialog.c',
+ 'gbp-shortcutui-row.c',
+ 'gbp-shortcutui-tweaks-addin.c',
+])
+
+plugin_shortcutui_resources = gnome.compile_resources(
+ 'shortcutui-resources',
+ 'shortcutui.gresource.xml',
+ c_name: 'gbp_shortcutui',
+)
+
+plugins_sources += plugin_shortcutui_resources
diff --git a/src/plugins/shortcutui/shortcutui-plugin.c b/src/plugins/shortcutui/shortcutui-plugin.c
new file mode 100644
index 000000000..ced514ea9
--- /dev/null
+++ b/src/plugins/shortcutui/shortcutui-plugin.c
@@ -0,0 +1,38 @@
+/* shortcutui-plugin.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 "shortcutui-plugin"
+
+#include "config.h"
+
+#include <libpeas/peas.h>
+
+#include <libide-gui.h>
+#include <libide-tweaks.h>
+
+#include "gbp-shortcutui-tweaks-addin.h"
+
+_IDE_EXTERN void
+_gbp_shortcutui_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_TWEAKS_ADDIN,
+ GBP_TYPE_SHORTCUTUI_TWEAKS_ADDIN);
+}
diff --git a/src/plugins/shortcutui/shortcutui.gresource.xml b/src/plugins/shortcutui/shortcutui.gresource.xml
new file mode 100644
index 000000000..0268b37b4
--- /dev/null
+++ b/src/plugins/shortcutui/shortcutui.gresource.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/plugins/shortcutui">
+ <file>shortcutui.plugin</file>
+ <file>style.css</file>
+ <file preprocess="xml-stripblanks">tweaks.ui</file>
+ <file preprocess="xml-stripblanks">gbp-shortcutui-dialog.ui</file>
+ <file preprocess="xml-stripblanks">gbp-shortcutui-row.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/plugins/shortcutui/shortcutui.plugin b/src/plugins/shortcutui/shortcutui.plugin
new file mode 100644
index 000000000..889db20d6
--- /dev/null
+++ b/src/plugins/shortcutui/shortcutui.plugin
@@ -0,0 +1,9 @@
+[Plugin]
+Authors=Christian Hergert <christian hergert me>
+Builtin=true
+Copyright=Copyright © 2022 Christian Hergert
+Depends=platformui;
+Embedded=_gbp_shortcutui_register_types
+Hidden=true
+Module=shortcutui
+Name=Shortcut Integration
diff --git a/src/plugins/shortcutui/style.css b/src/plugins/shortcutui/style.css
new file mode 100644
index 000000000..5d0892b5a
--- /dev/null
+++ b/src/plugins/shortcutui/style.css
@@ -0,0 +1,8 @@
+window.shortcutui list.search row.has-header {
+ border-top: 1px solid @borders;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+window.shortcutui list.search label.heading {
+ padding: 10px 12px 12px 16px;
+}
diff --git a/src/plugins/shortcutui/tweaks.ui b/src/plugins/shortcutui/tweaks.ui
new file mode 100644
index 000000000..27950a4b4
--- /dev/null
+++ b/src/plugins/shortcutui/tweaks.ui
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="IdeTweaks">
+ <child internal-child="visual_section">
+ <object class="IdeTweaksSection">
+ <child>
+ <object class="IdeTweaksPage" id="shortcuts_page">
+ <property name="title" translatable="yes">Keyboard Shortcuts</property>
+ <property name="icon-name">preferences-desktop-keyboard-shortcuts-symbolic</property>
+ <child>
+ <object class="IdeTweaksGroup">
+ <property name="title" translatable="yes">Keyboard Shortcuts</property>
+ <child>
+ <object class="IdeTweaksWidget">
+ <signal name="create-for-item" handler="shortcutui_create_shortcuts_cb"
object="GbpShortcutuiTweaksAddin" swapped="true"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]