[gnome-text-editor] spellcheck: add custom GMenuModel for corrections



commit f80164d1e14e9a6334b279c8d57a746f00d6d8a7
Author: Christian Hergert <chergert redhat com>
Date:   Fri Nov 12 13:36:43 2021 -0800

    spellcheck: add custom GMenuModel for corrections
    
    This allows us to replace the corrections in a single
    GMenuModel::items-changed() signal. Unfortunately, even that is not enough
    to improve the cost of GTK action muxer updates.
    
    Related #220

 src/editor-spell-menu.c | 133 ++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 117 insertions(+), 16 deletions(-)
---
diff --git a/src/editor-spell-menu.c b/src/editor-spell-menu.c
index 36c68f6..da4ba88 100644
--- a/src/editor-spell-menu.c
+++ b/src/editor-spell-menu.c
@@ -28,6 +28,118 @@
 
 #define MAX_CORRECTIONS 5
 
+#define EDITOR_TYPE_SPELL_CORRECTIONS (editor_spell_corrections_get_type())
+G_DECLARE_FINAL_TYPE (EditorSpellCorrections, editor_spell_corrections, EDITOR, SPELL_CORRECTIONS, 
GMenuModel)
+
+struct _EditorSpellCorrections
+{
+  GMenuModel parent_instance;
+  char **corrections;
+};
+
+G_DEFINE_TYPE (EditorSpellCorrections, editor_spell_corrections, G_TYPE_MENU_MODEL)
+
+static int
+editor_spell_corrections_get_n_items (GMenuModel *model)
+{
+  EditorSpellCorrections *self = EDITOR_SPELL_CORRECTIONS (model);
+  return self->corrections ? g_strv_length (self->corrections) : 0;
+}
+
+static gboolean
+editor_spell_corrections_is_mutable (GMenuModel *model)
+{
+  return TRUE;
+}
+
+static GMenuModel *
+editor_spell_corrections_get_item_link (GMenuModel *model,
+                                        int         position,
+                                        const char *link)
+{
+  return NULL;
+}
+
+static void
+editor_spell_corrections_get_item_links (GMenuModel  *model,
+                                         int          position,
+                                         GHashTable **links)
+{
+  *links = NULL;
+}
+
+static void
+editor_spell_corrections_get_item_attributes (GMenuModel  *model,
+                                              int          position,
+                                              GHashTable **attributes)
+{
+  EditorSpellCorrections *self = EDITOR_SPELL_CORRECTIONS (model);
+  const char *correction;
+  GHashTable *ht;
+
+  *attributes = NULL;
+
+  if (position < 0 ||
+      self->corrections == NULL ||
+      position >= g_strv_length (self->corrections))
+    return;
+
+  correction = self->corrections[position];
+
+  ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
+  g_hash_table_insert (ht, g_strdup (G_MENU_ATTRIBUTE_ACTION), g_variant_ref_sink (g_variant_new_string 
("spelling.correct")));
+  g_hash_table_insert (ht, g_strdup (G_MENU_ATTRIBUTE_TARGET), g_variant_ref_sink (g_variant_new_string 
(correction)));
+  g_hash_table_insert (ht, g_strdup (G_MENU_ATTRIBUTE_LABEL), g_variant_ref_sink (g_variant_new_string 
(correction)));
+
+  *attributes = ht;
+}
+
+static void
+editor_spell_corrections_class_init (EditorSpellCorrectionsClass *klass)
+{
+  GMenuModelClass *menu_model_class = G_MENU_MODEL_CLASS (klass);
+
+  menu_model_class->get_n_items = editor_spell_corrections_get_n_items;
+  menu_model_class->is_mutable = editor_spell_corrections_is_mutable;
+  menu_model_class->get_item_link = editor_spell_corrections_get_item_link;
+  menu_model_class->get_item_links = editor_spell_corrections_get_item_links;
+  menu_model_class->get_item_attributes = editor_spell_corrections_get_item_attributes;
+}
+
+static void
+editor_spell_corrections_init (EditorSpellCorrections *self)
+{
+}
+
+static void
+editor_spell_corrections_set (EditorSpellCorrections *self,
+                              const char * const     *corrections)
+{
+  guint removed = 0;
+  guint added = 0;
+
+  g_assert (EDITOR_IS_SPELL_CORRECTIONS (self));
+
+  if (corrections == (const char * const *)self->corrections)
+    return;
+
+  if (self->corrections != NULL)
+    removed = g_strv_length (self->corrections);
+
+  if (corrections != NULL)
+    added = g_strv_length ((char **)corrections);
+
+  g_strfreev (self->corrections);
+  self->corrections = g_strdupv ((char **)corrections);
+  g_menu_model_items_changed (G_MENU_MODEL (self), 0, removed, added);
+}
+
+static GMenuModel *
+editor_spell_corrections_new (void)
+{
+  return g_object_new (EDITOR_TYPE_SPELL_CORRECTIONS, NULL);
+}
+
 static void
 populate_languages (GMenu *menu)
 {
@@ -53,7 +165,7 @@ GMenuModel *
 editor_spell_menu_new (void)
 {
   g_autoptr(GMenu) menu = g_menu_new ();
-  g_autoptr(GMenu) corrections_menu = g_menu_new ();
+  g_autoptr(GMenuModel) corrections_menu = editor_spell_corrections_new ();
   g_autoptr(GMenu) languages_menu = g_menu_new ();
   g_autoptr(GMenuItem) languages_item = g_menu_item_new_submenu (_("Languages"), G_MENU_MODEL 
(languages_menu));
   g_autoptr(GMenuItem) add_item = g_menu_item_new (_("Add to Dictionary"), "spelling.add");
@@ -90,24 +202,13 @@ void
 editor_spell_menu_set_corrections (GMenuModel         *menu,
                                    const char * const *words)
 {
-  GMenu *corrections_menu;
+  EditorSpellCorrections *corrections_menu;
 
   g_return_if_fail (G_IS_MENU_MODEL (menu));
 
-  if (!(corrections_menu = g_object_get_data (G_OBJECT (menu), "CORRECTIONS_MENU")))
-    g_return_if_reached ();
-
-  while (g_menu_model_get_n_items (G_MENU_MODEL (corrections_menu)))
-    g_menu_remove (corrections_menu, 0);
-
-  if (words == NULL)
-    return;
-
-  for (guint i = 0; i < MAX_CORRECTIONS && words[i]; i++)
+  if ((corrections_menu = g_object_get_data (G_OBJECT (menu), "CORRECTIONS_MENU")))
     {
-      g_autoptr(GMenuItem) item = g_menu_item_new (words[i], NULL);
-
-      g_menu_item_set_action_and_target (item, "spelling.correct", "s", words[i]);
-      g_menu_append_item (corrections_menu, item);
+      g_assert (EDITOR_IS_SPELL_CORRECTIONS (corrections_menu));
+      editor_spell_corrections_set (corrections_menu, words);
     }
 }


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