[gnome-builder/wip/chergert/shortcut-editing: 1/2] libide/gui: improve shortcut discovery




commit 02d3fc38ddad5c2c34db7915dfcad392a0551db8
Author: Christian Hergert <chergert redhat com>
Date:   Mon Oct 3 21:38:12 2022 -0700

    libide/gui: improve shortcut discovery

 src/libide/gui/ide-shortcut-bundle-private.h | 11 +++++
 src/libide/gui/ide-shortcut-bundle.c         | 16 +++-----
 src/libide/gui/ide-shortcut-info.h           |  3 +-
 src/libide/gui/ide-shortcut-window.c         | 61 ++++++++++++++++++++++++----
 4 files changed, 71 insertions(+), 20 deletions(-)
---
diff --git a/src/libide/gui/ide-shortcut-bundle-private.h b/src/libide/gui/ide-shortcut-bundle-private.h
index 1f8ec5183..6d67cfa8e 100644
--- a/src/libide/gui/ide-shortcut-bundle-private.h
+++ b/src/libide/gui/ide-shortcut-bundle-private.h
@@ -20,12 +20,23 @@
 
 #pragma once
 
+#include <gtk/gtk.h>
+#include <tmpl-glib.h>
+
 #include <libide-core.h>
 
 G_BEGIN_DECLS
 
 #define IDE_TYPE_SHORTCUT_BUNDLE (ide_shortcut_bundle_get_type())
 
+typedef struct
+{
+  TmplExpr            *when;
+  GVariant            *args;
+  GtkShortcutAction   *action;
+  GtkPropagationPhase  phase;
+} IdeShortcut;
+
 G_DECLARE_FINAL_TYPE (IdeShortcutBundle, ide_shortcut_bundle, IDE, SHORTCUT_BUNDLE, GObject)
 
 IdeShortcutBundle *ide_shortcut_bundle_new   (void);
diff --git a/src/libide/gui/ide-shortcut-bundle.c b/src/libide/gui/ide-shortcut-bundle.c
index df23db0e1..83cac9632 100644
--- a/src/libide/gui/ide-shortcut-bundle.c
+++ b/src/libide/gui/ide-shortcut-bundle.c
@@ -38,14 +38,6 @@ struct _IdeShortcutBundle
   GPtrArray *items;
 };
 
-typedef struct
-{
-  TmplExpr            *when;
-  GVariant            *args;
-  GtkShortcutAction   *action;
-  GtkPropagationPhase  phase;
-} IdeShortcut;
-
 static TmplScope *imports_scope;
 
 static IdeShortcut *
@@ -61,7 +53,7 @@ ide_shortcut_new (const char          *action,
 
   ret = g_slice_new0 (IdeShortcut);
   ret->action = gtk_named_action_new (action);
-  ret->args = args ? g_variant_ref (args) : NULL;
+  ret->args = args ? g_variant_ref_sink (args) : NULL;
   ret->when = when ? tmpl_expr_ref (when) : NULL;
   ret->phase = phase;
 
@@ -315,6 +307,7 @@ populate_from_object (IdeShortcutBundle  *self,
   const char *phase_str = NULL;
   const char *command = NULL;
   const char *action = NULL;
+  IdeShortcut *state;
   GtkPropagationPhase phase = 0;
   JsonObject *obj;
 
@@ -396,12 +389,13 @@ populate_from_object (IdeShortcutBundle  *self,
       return FALSE;
     }
 
-  callback = gtk_callback_action_new (ide_shortcut_activate,
-                                      ide_shortcut_new (action, args, when, phase),
+  state = ide_shortcut_new (action, args, when, phase);
+  callback = gtk_callback_action_new (ide_shortcut_activate, state,
                                       (GDestroyNotify) ide_shortcut_free);
   shortcut = gtk_shortcut_new (g_steal_pointer (&trigger),
                                g_steal_pointer (&callback));
   g_object_set_data (G_OBJECT (shortcut), "PHASE", GINT_TO_POINTER (phase));
+  g_object_set_data (G_OBJECT (shortcut), "IDE_SHORTCUT", state);
   g_ptr_array_add (self->items, g_steal_pointer (&shortcut));
 
   return TRUE;
diff --git a/src/libide/gui/ide-shortcut-info.h b/src/libide/gui/ide-shortcut-info.h
index 0e6249d4a..fda0b3fca 100644
--- a/src/libide/gui/ide-shortcut-info.h
+++ b/src/libide/gui/ide-shortcut-info.h
@@ -30,7 +30,8 @@ typedef void (*IdeShortcutInfoFunc) (const IdeShortcutInfo *info,
                                      gpointer               user_data);
 
 IDE_AVAILABLE_IN_44
-void        ide_shortcut_info_foreach           (const IdeShortcutInfoFunc  func,
+void        ide_shortcut_info_foreach           (GListModel                *shortcuts,
+                                                 const IdeShortcutInfoFunc  func,
                                                  gpointer                   func_data);
 IDE_AVAILABLE_IN_44
 const char *ide_shortcut_info_get_accelerator   (const IdeShortcutInfo     *self);
diff --git a/src/libide/gui/ide-shortcut-window.c b/src/libide/gui/ide-shortcut-window.c
index a52829c7d..d8849e77c 100644
--- a/src/libide/gui/ide-shortcut-window.c
+++ b/src/libide/gui/ide-shortcut-window.c
@@ -27,6 +27,7 @@
 #include <libide-gtk.h>
 
 #include "ide-application-private.h"
+#include "ide-shortcut-bundle-private.h"
 #include "ide-shortcut-info.h"
 #include "ide-shortcut-window-private.h"
 
@@ -118,7 +119,7 @@ page_info_free (PageInfo *pi)
   g_slice_free (PageInfo, pi);
 }
 
-static const char *
+static char *
 find_accel_for_action (GHashTable *accel_map,
                        const char *action)
 {
@@ -132,7 +133,7 @@ find_accel_for_action (GHashTable *accel_map,
     return NULL;
 
   if ((accel = g_hash_table_lookup (accel_map, action)))
-    return accel;
+    return g_strdup (accel);
 
   if ((split = strstr (action, "::")))
     alt = g_strdup (split + 2);
@@ -141,7 +142,7 @@ find_accel_for_action (GHashTable *accel_map,
   else
     return NULL;
 
-  return g_hash_table_lookup (accel_map, alt);
+  return g_strdup (g_hash_table_lookup (accel_map, alt));
 }
 
 static void
@@ -165,11 +166,11 @@ populate_from_menu_model (GQueue     *queue,
       g_autofree char *icon_name = NULL;
       g_autofree char *item_group = NULL;
       g_autofree char *item_page = NULL;
+      g_autofree char *accel = NULL;
       g_autofree char *subtitle = NULL;
       g_autofree char *title = NULL;
       g_autoptr(GVariant) target = NULL;
       ShortcutInfo *si;
-      const char *accel;
 
       if (!g_menu_model_get_item_attribute (menu, i, "action", "s", &action))
         continue;
@@ -190,7 +191,7 @@ populate_from_menu_model (GQueue     *queue,
 
       si = g_slice_new0 (ShortcutInfo);
       si->link.data = si;
-      si->accel = g_strdup (accel);
+      si->accel = g_steal_pointer (&accel);
       si->icon_name = g_steal_pointer (&icon_name);
       si->subtitle = g_steal_pointer (&subtitle);
       si->title = g_steal_pointer (&title);
@@ -524,17 +525,61 @@ struct _IdeShortcutInfo
   GVariant *action_target;
 };
 
+/**
+ * ide_shortcut_info_foreach:
+ * @shortcuts: a #GListModel of #GtkShortcut
+ * @func: (scope call): a callback for each shortcut info
+ * @func_data: closure data for @func
+ *
+ * Calls @func for every shortcut info. Accelerators come from
+ * @shortcuts by matching action and target.
+ */
 void
-ide_shortcut_info_foreach (const IdeShortcutInfoFunc func,
-                           gpointer                  func_data)
+ide_shortcut_info_foreach (GListModel                *shortcuts,
+                           const IdeShortcutInfoFunc  func,
+                           gpointer                   func_data)
 {
   g_autoptr(GHashTable) accel_map = NULL;
   GQueue pages = G_QUEUE_INIT;
   IdeShortcutInfo info = {0};
 
   g_return_if_fail (func != NULL);
+  g_return_if_fail (!shortcuts || G_IS_LIST_MODEL (shortcuts));
+
+  accel_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  if (shortcuts != NULL)
+    {
+      guint n_items = g_list_model_get_n_items (shortcuts);
+
+      /* First build a hashmap of action names to shortcut triggers */
+      for (guint i = n_items; i > 0; i--)
+        {
+          g_autoptr(GtkShortcut) shortcut = g_list_model_get_item (shortcuts, i-1);
+          GtkShortcutTrigger *trigger = gtk_shortcut_get_trigger (shortcut);
+          GtkShortcutAction *action = gtk_shortcut_get_action (shortcut);
+          IdeShortcut *state;
+
+          if (GTK_IS_NAMED_ACTION (action))
+            {
+              g_autofree char *accel = gtk_shortcut_trigger_to_string (trigger);
+              const char *name = gtk_named_action_get_action_name (GTK_NAMED_ACTION (action));
+
+              g_hash_table_insert (accel_map, g_strdup (name), g_steal_pointer (&accel));
+            }
+          else if ((state = g_object_get_data (G_OBJECT (shortcut), "IDE_SHORTCUT")) &&
+                   GTK_IS_NAMED_ACTION (state->action))
+            {
+              g_autofree char *accel = gtk_shortcut_trigger_to_string (trigger);
+              const char *name = gtk_named_action_get_action_name (GTK_NAMED_ACTION (state->action));
+
+              g_hash_table_insert (accel_map,
+                                   g_strdup (name),
+                                   g_steal_pointer (&accel));
+            }
+        }
+    }
 
-  accel_map = g_hash_table_new (NULL, NULL);
   populate_info (&pages, accel_map);
 
   for (const GList *piter = pages.head; piter; piter = piter->next)


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