[gnome-builder/wip/gtk4-port] libide/gui: move internal shortcut loading into manager



commit 5226ce38375478af7d5b04a4b9ec8be384866e39
Author: Christian Hergert <chergert redhat com>
Date:   Fri May 6 22:27:18 2022 -0700

    libide/gui: move internal shortcut loading into manager
    
    This will give us a bit easier time controlling how this stuff loads as
    we begin to migrate plugins to using keybindings.json.

 src/libide/gui/ide-shortcut-controller.c           |  62 -------
 ...er-private.h => ide-shortcut-manager-private.h} |  16 +-
 src/libide/gui/ide-shortcut-manager.c              | 196 +++++++++++++++++++++
 src/libide/gui/ide-shortcut-model-private.h        |  41 -----
 src/libide/gui/ide-shortcut-model.c                | 187 --------------------
 src/libide/gui/ide-workbench.c                     |  71 ++------
 src/libide/gui/ide-workbench.h                     |   2 -
 src/libide/gui/ide-workspace.c                     |   6 -
 src/libide/gui/meson.build                         |   6 +-
 9 files changed, 225 insertions(+), 362 deletions(-)
---
diff --git a/src/libide/gui/ide-shortcut-controller-private.h b/src/libide/gui/ide-shortcut-manager-private.h
similarity index 53%
rename from src/libide/gui/ide-shortcut-controller-private.h
rename to src/libide/gui/ide-shortcut-manager-private.h
index 9215dff23..7cb55f5e1 100644
--- a/src/libide/gui/ide-shortcut-controller-private.h
+++ b/src/libide/gui/ide-shortcut-manager-private.h
@@ -1,4 +1,4 @@
-/* ide-shortcut-controller-private.h
+/* ide-shortcut-manager-private.h
  *
  * Copyright 2022 Christian Hergert <chergert redhat com>
  *
@@ -20,10 +20,20 @@
 
 #pragma once
 
-#include <gtk/gtk.h>
+#include <libpeas/peas.h>
+
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
-GtkEventController *ide_shortcut_controller_new_for_window (GtkWindow *window);
+#define IDE_TYPE_SHORTCUT_MANAGER (ide_shortcut_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeShortcutManager, ide_shortcut_manager, IDE, SHORTCUT_MANAGER, IdeObject)
+
+IdeShortcutManager *ide_shortcut_manager_from_context    (IdeContext           *context);
+void                ide_shortcut_manager_add_plugin      (IdeShortcutManager   *self,
+                                                          const PeasPluginInfo *plugin_info);
+void                ide_shortcut_manager_remove_plugin   (IdeShortcutManager   *self,
+                                                          const PeasPluginInfo *plugin_info);
 
 G_END_DECLS
diff --git a/src/libide/gui/ide-shortcut-manager.c b/src/libide/gui/ide-shortcut-manager.c
new file mode 100644
index 000000000..44a3172f0
--- /dev/null
+++ b/src/libide/gui/ide-shortcut-manager.c
@@ -0,0 +1,196 @@
+/* ide-shortcut-manager.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 "ide-shortcut-manager"
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include "ide-shortcut-bundle-private.h"
+#include "ide-shortcut-manager-private.h"
+
+struct _IdeShortcutManager
+{
+  IdeObject   parent_instance;
+
+  /* Holds [plugin_models,internal_models] so that plugin models take
+   * priority over the others.
+   */
+  GListStore *toplevel;
+
+  /* Holds bundles loaded from plugins, more recently loaded plugins
+   * towards the head of the list.
+   *
+   * Plugins loaded dynamically could change ordering here, which might
+   * be something we want to address someday. In practice, it doesn't
+   * happen very often and people restart applications often.
+   */
+  GListStore *plugin_models;
+
+  /* A flattened list model we proxy through our interface */
+  GtkFlattenListModel *flatten;
+};
+
+static GType
+ide_shortcut_manager_get_item_type (GListModel *model)
+{
+  return GTK_TYPE_SHORTCUT;
+}
+
+static guint
+ide_shortcut_manager_get_n_items (GListModel *model)
+{
+  IdeShortcutManager *self = IDE_SHORTCUT_MANAGER (model);
+
+  if (self->flatten)
+    return g_list_model_get_n_items (G_LIST_MODEL (self->flatten));
+
+  return 0;
+}
+
+static gpointer
+ide_shortcut_manager_get_item (GListModel *model,
+                               guint       position)
+{
+  IdeShortcutManager *self = IDE_SHORTCUT_MANAGER (model);
+
+  if (self->flatten)
+    return g_list_model_get_item (G_LIST_MODEL (self->flatten), position);
+
+  return NULL;
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+  iface->get_item_type = ide_shortcut_manager_get_item_type;
+  iface->get_n_items = ide_shortcut_manager_get_n_items;
+  iface->get_item = ide_shortcut_manager_get_item;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (IdeShortcutManager, ide_shortcut_manager, IDE_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
+
+static GListModel *
+get_internal_models (void)
+{
+  static GListStore *internal_models;
+
+  if (internal_models == NULL)
+    {
+      static const char *names[] = {
+        "libide-gui",
+      };
+
+      internal_models = g_list_store_new (G_TYPE_LIST_MODEL);
+
+      for (guint i = 0; i < G_N_ELEMENTS (names); i++)
+        {
+          g_autoptr(IdeShortcutBundle) bundle = ide_shortcut_bundle_new ();
+          g_autofree char *uri = g_strdup_printf ("resource:///org/gnome/%s/gtk/keybindings.json", names[i]);
+          g_autoptr(GFile) file = g_file_new_for_uri (uri);
+          g_autoptr(GError) error = NULL;
+
+          if (!g_file_query_exists (file, NULL))
+            continue;
+
+          if (!ide_shortcut_bundle_parse (bundle, file, &error))
+            g_critical ("Failed to parse %s: %s", uri, error->message);
+          else
+            g_list_store_append (internal_models, bundle);
+        }
+    }
+
+  return G_LIST_MODEL (internal_models);
+}
+
+static void
+ide_shortcut_manager_items_changed_cb (IdeShortcutManager *self,
+                                       guint               position,
+                                       guint               removed,
+                                       guint               added,
+                                       GListModel         *model)
+{
+  g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
+}
+
+static void
+ide_shortcut_manager_dispose (GObject *object)
+{
+  IdeShortcutManager *self = (IdeShortcutManager *)object;
+
+  g_clear_object (&self->toplevel);
+  g_clear_object (&self->plugin_models);
+  g_clear_object (&self->flatten);
+
+  G_OBJECT_CLASS (ide_shortcut_manager_parent_class)->dispose (object);
+}
+
+static void
+ide_shortcut_manager_class_init (IdeShortcutManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_shortcut_manager_dispose;
+}
+
+static void
+ide_shortcut_manager_init (IdeShortcutManager *self)
+{
+  self->toplevel = g_list_store_new (G_TYPE_LIST_MODEL);
+  self->plugin_models = g_list_store_new (G_TYPE_LIST_MODEL);
+  g_list_store_append (self->toplevel, G_LIST_MODEL (self->plugin_models));
+  g_list_store_append (self->toplevel, get_internal_models ());
+
+  self->flatten = gtk_flatten_list_model_new (g_object_ref (G_LIST_MODEL (self->toplevel)));
+  g_signal_connect_object (self->flatten,
+                           "items-changed",
+                           G_CALLBACK (ide_shortcut_manager_items_changed_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+/**
+ * ide_shortcut_manager_from_context:
+ * @context: an #IdeContext
+ *
+ * Gets the shortcut manager for the contenxt
+ *
+ * Returns: (transfer none): an #IdeShortcutManager
+ */
+IdeShortcutManager *
+ide_shortcut_manager_from_context (IdeContext *context)
+{
+  IdeShortcutManager *ret;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  if (!(ret = ide_context_peek_child_typed (context, IDE_TYPE_SHORTCUT_MANAGER)))
+    {
+      g_autoptr(IdeObject) child = NULL;
+
+      child = ide_object_ensure_child_typed (IDE_OBJECT (context), IDE_TYPE_SHORTCUT_MANAGER);
+      ret = ide_context_peek_child_typed (context, IDE_TYPE_SHORTCUT_MANAGER);
+    }
+
+  return ret;
+}
diff --git a/src/libide/gui/ide-workbench.c b/src/libide/gui/ide-workbench.c
index d9c35de8b..d9f3f0618 100644
--- a/src/libide/gui/ide-workbench.c
+++ b/src/libide/gui/ide-workbench.c
@@ -40,7 +40,7 @@
 #include "ide-gui-global.h"
 #include "ide-preferences-window.h"
 #include "ide-primary-workspace.h"
-#include "ide-shortcut-bundle-private.h"
+#include "ide-shortcut-manager-private.h"
 #include "ide-workbench-addin.h"
 #include "ide-workbench-private.h"
 #include "ide-workspace-private.h"
@@ -75,8 +75,6 @@ struct _IdeWorkbench
   IdeVcs              *vcs;
   IdeVcsMonitor       *vcs_monitor;
   IdeSearchEngine     *search_engine;
-  GListStore          *shortcut_bundles;
-  GtkFlattenListModel *shortcuts;
 
   /* Various flags */
   guint                unloaded : 1;
@@ -183,26 +181,6 @@ ignore_error (GError *error)
          g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
 }
 
-static IdeShortcutBundle *
-get_internal_shortcuts (void)
-{
-  static IdeShortcutBundle *internal_shortcuts;
-
-  if (internal_shortcuts == NULL)
-    {
-      g_autoptr(GFile) file = NULL;
-      g_autoptr(GError) error = NULL;
-
-      file = g_file_new_for_uri ("resource:///org/gnome/libide-gui/gtk/keybindings.json");
-      internal_shortcuts = ide_shortcut_bundle_new ();
-
-      if (!ide_shortcut_bundle_parse (internal_shortcuts, file, &error))
-        g_critical ("Failed to parse keybindings.json: %s", error->message);
-    }
-
-  return internal_shortcuts;
-}
-
 /**
  * ide_workbench_from_context:
  * @context: an #IdeContext
@@ -419,8 +397,6 @@ ide_workbench_finalize (GObject *object)
   if (self->context != NULL)
     g_object_set_data (G_OBJECT (self->context), "WORKBENCH", NULL);
 
-  g_clear_object (&self->shortcut_bundles);
-  g_clear_object (&self->shortcuts);
   g_clear_object (&self->build_system);
   g_clear_object (&self->vcs);
   g_clear_object (&self->search_engine);
@@ -524,11 +500,6 @@ static void
 ide_workbench_init (IdeWorkbench *self)
 {
   ide_workbench_set_action_enabled (self, "configure", FALSE);
-
-  /* Setup shortcuts */
-  self->shortcut_bundles = g_list_store_new (IDE_TYPE_SHORTCUT_BUNDLE);
-  g_list_store_append (self->shortcut_bundles, get_internal_shortcuts ());
-  self->shortcuts = gtk_flatten_list_model_new (g_object_ref (G_LIST_MODEL (self->shortcut_bundles)));
 }
 
 static void
@@ -802,8 +773,9 @@ ide_workbench_add_workspace (IdeWorkbench *self,
   g_autoptr(GPtrArray) addins = NULL;
   g_autoptr(GtkFilterListModel) capture = NULL;
   g_autoptr(GtkFilterListModel) bubble = NULL;
+  IdeShortcutManager *shortcuts;
+  GtkEventController *controller;
   IdeCommandManager *command_manager;
-  GtkEventController *shortcuts;
   GList *mru_link;
 
   g_return_if_fail (IDE_IS_MAIN_THREAD ());
@@ -847,20 +819,21 @@ ide_workbench_add_workspace (IdeWorkbench *self,
     insert_action_groups_foreach_cb (workspace, self);
 
   /* Setup capture shortcut controller for workspace */
-  capture = gtk_filter_list_model_new (g_object_ref (G_LIST_MODEL (self->shortcuts)),
+  shortcuts = ide_shortcut_manager_from_context (self->context);
+  capture = gtk_filter_list_model_new (g_object_ref (G_LIST_MODEL (shortcuts)),
                                        create_shortcut_filter (GTK_PHASE_CAPTURE));
-  shortcuts = gtk_shortcut_controller_new_for_model (G_LIST_MODEL (g_steal_pointer (&capture)));
-  gtk_event_controller_set_name (shortcuts, "ide-shortcuts-capture");
-  gtk_event_controller_set_propagation_phase (shortcuts, GTK_PHASE_CAPTURE);
-  gtk_widget_add_controller (GTK_WIDGET (workspace), shortcuts);
+  controller = gtk_shortcut_controller_new_for_model (G_LIST_MODEL (g_steal_pointer (&capture)));
+  gtk_event_controller_set_name (controller, "ide-shortcuts-capture");
+  gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
+  gtk_widget_add_controller (GTK_WIDGET (workspace), controller);
 
   /* Setup bubble shortcut controller for workspace */
-  bubble = gtk_filter_list_model_new (g_object_ref (G_LIST_MODEL (self->shortcuts)),
+  bubble = gtk_filter_list_model_new (g_object_ref (G_LIST_MODEL (shortcuts)),
                                       create_shortcut_filter (GTK_PHASE_BUBBLE));
-  shortcuts = gtk_shortcut_controller_new_for_model (G_LIST_MODEL (g_steal_pointer (&bubble)));
-  gtk_event_controller_set_name (shortcuts, "ide-shortcuts-bubble");
-  gtk_event_controller_set_propagation_phase (shortcuts, GTK_PHASE_BUBBLE);
-  gtk_widget_add_controller (GTK_WIDGET (workspace), shortcuts);
+  controller = gtk_shortcut_controller_new_for_model (G_LIST_MODEL (g_steal_pointer (&bubble)));
+  gtk_event_controller_set_name (controller, "ide-shortcuts-bubble");
+  gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
+  gtk_widget_add_controller (GTK_WIDGET (workspace), controller);
 
   /* Track toplevel focus changes to maintain a most-recently-used queue. */
   g_signal_connect_object (workspace,
@@ -2736,19 +2709,3 @@ ide_workbench_action_configure (IdeWorkbench *self,
       gtk_window_present (window);
     }
 }
-
-/**
- * ide_workbench_get_shortcuts:
- * @self: a #IdeWorkbench
- *
- * Gets a [iface@Gio.ListModel] of [class@Gtk.Shortcut]s.
- *
- * Returns: (transfer none): a #GListModel
- */
-GListModel *
-ide_workbench_get_shortcuts (IdeWorkbench *self)
-{
-  g_return_val_if_fail (IDE_IS_WORKBENCH (self), NULL);
-
-  return G_LIST_MODEL (self->shortcuts);
-}
diff --git a/src/libide/gui/ide-workbench.h b/src/libide/gui/ide-workbench.h
index 8d9c356c9..b534049b8 100644
--- a/src/libide/gui/ide-workbench.h
+++ b/src/libide/gui/ide-workbench.h
@@ -61,8 +61,6 @@ IdeWorkspace    *ide_workbench_get_workspace_by_type (IdeWorkbench         *self
 IDE_AVAILABLE_IN_ALL
 IdeSearchEngine *ide_workbench_get_search_engine     (IdeWorkbench         *self);
 IDE_AVAILABLE_IN_ALL
-GListModel      *ide_workbench_get_shortcuts         (IdeWorkbench         *self);
-IDE_AVAILABLE_IN_ALL
 IdeWorkbench    *ide_workbench_from_widget           (GtkWidget            *widget);
 IDE_AVAILABLE_IN_ALL
 void             ide_workbench_add_workspace         (IdeWorkbench         *self,
diff --git a/src/libide/gui/ide-workspace.c b/src/libide/gui/ide-workspace.c
index 2c998a6c8..02bbdca83 100644
--- a/src/libide/gui/ide-workspace.c
+++ b/src/libide/gui/ide-workspace.c
@@ -27,7 +27,6 @@
 
 #include "ide-gui-global.h"
 #include "ide-search-popover-private.h"
-#include "ide-shortcut-controller-private.h"
 #include "ide-workspace-addin.h"
 #include "ide-workspace-private.h"
 #include "ide-workbench-private.h"
@@ -565,7 +564,6 @@ static void
 ide_workspace_init (IdeWorkspace *self)
 {
   IdeWorkspacePrivate *priv = ide_workspace_get_instance_private (self);
-  GtkEventController *shortcuts;
   g_autofree gchar *app_id = NULL;
 
 #ifdef DEVELOPMENT_BUILD
@@ -600,10 +598,6 @@ ide_workspace_init (IdeWorkspace *self)
 
   /* Initialize GActions for workspace */
   _ide_workspace_init_actions (self);
-
-  /* Initialize shortcuts for the window */
-  shortcuts = ide_shortcut_controller_new_for_window (GTK_WINDOW (self));
-  gtk_widget_add_controller (GTK_WIDGET (self), shortcuts);
 }
 
 GList *
diff --git a/src/libide/gui/meson.build b/src/libide/gui/meson.build
index 0c5909b3f..c516c66a3 100644
--- a/src/libide/gui/meson.build
+++ b/src/libide/gui/meson.build
@@ -56,8 +56,7 @@ libide_gui_private_headers = [
   'ide-search-popover-private.h',
   'ide-session-private.h',
   'ide-shortcut-bundle-private.h',
-  'ide-shortcut-model-private.h',
-  'ide-shortcut-controller-private.h',
+  'ide-shortcut-manager-private.h',
   'ide-style-variant-preview-private.h',
 ]
 
@@ -76,8 +75,7 @@ libide_gui_private_sources = [
   'ide-search-popover.c',
   'ide-session.c',
   'ide-shortcut-bundle.c',
-  'ide-shortcut-model.c',
-  'ide-shortcut-controller.c',
+  'ide-shortcut-manager.c',
   'ide-style-variant-preview.c',
   'ide-workspace-actions.c',
 ]


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