[gtk+/gtk-3-22] Redo emoji data slightly



commit c56545f7211664ccccb27a5771835465260ebea7
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Aug 13 15:16:11 2017 -0400

    Redo emoji data slightly
    
    No longer store variation sequences explicitly. Instead, put a 0
    in the sequence where the modifiers will be inserted. This is more
    compact, and it allows us to put variations directly into the
    recent section. Update the type of the recent-emoji setting to
    match these changes.

 gtk/emoji/convert-emoji.c                     |  222 +++++++++++++------------
 gtk/emoji/emoji.data                          |  Bin 53562 -> 36967 bytes
 gtk/gtkemojichooser.c                         |  138 +++++++++-------
 gtk/org.gtk.Settings.EmojiChooser.gschema.xml |    7 +-
 4 files changed, 200 insertions(+), 167 deletions(-)
---
diff --git a/gtk/emoji/convert-emoji.c b/gtk/emoji/convert-emoji.c
index 7850ccc..3474259 100644
--- a/gtk/emoji/convert-emoji.c
+++ b/gtk/emoji/convert-emoji.c
@@ -22,28 +22,31 @@
 #include <string.h>
 
 gboolean
-parse_code (GVariantBuilder *b, const char *code)
+parse_code (GVariantBuilder *b,
+            const char      *code)
 {
-        g_auto(GStrv) strv = NULL;
-        int j;
-        guint32 u1;
-
-        strv = g_strsplit (code, " ", -1);
-        for (j = 0; strv[j]; j++) {
-                guint32 u;
-                char *end;
-
-                u = (guint32) g_ascii_strtoull (strv[j], &end, 16);
-                if (*end != '\0') {
-                        g_error ("failed to parse code: %s\n", strv[j]);
-                        return FALSE;
-                }
-                //if (u != 0xfe0f || strv[j+1] != 0)
-                        g_variant_builder_add (b, "u", u);
-                u1 = u;
+  g_auto(GStrv) strv = NULL;
+  int j;
+
+  strv = g_strsplit (code, " ", -1);
+  for (j = 0; strv[j]; j++)
+    {
+      guint32 u;
+      char *end;
+
+      u = (guint32) g_ascii_strtoull (strv[j], &end, 16);
+      if (*end != '\0')
+        {
+          g_error ("failed to parse code: %s\n", strv[j]);
+          return FALSE;
         }
+      if (0x1f3fb <= u && u <= 0x1f3ff)
+        g_variant_builder_add (b, "u", 0);
+      else
+        g_variant_builder_add (b, "u", u);
+    }
 
-        return TRUE;
+  return TRUE;
 }
 
 static const char *blacklist[] = {
@@ -78,97 +81,102 @@ static const char *blacklist[] = {
 int
 main (int argc, char *argv[])
 {
-        JsonParser *parser;
-        JsonNode *root;
-        JsonArray *array;
-        GError *error = NULL;
-        guint length, i;
-        GVariantBuilder builder;
-        GVariant *v;
-        GString *s;
-        GBytes *bytes;
-
-        if (argc != 3) {
-                g_print ("Usage: emoji-convert INPUT OUTPUT\n");
-                return 1;
+  JsonParser *parser;
+  JsonNode *root;
+  JsonArray *array;
+  GError *error = NULL;
+  guint length, i;
+  GVariantBuilder builder;
+  GVariant *v;
+  GString *s;
+  GBytes *bytes;
+
+  if (argc != 3)
+    {
+      g_print ("Usage: emoji-convert INPUT OUTPUT\n");
+      return 1;
+    }
+
+  parser = json_parser_new ();
+
+  if (!json_parser_load_from_file (parser, argv[1], &error))
+    {
+      g_error ("%s", error->message);
+      return 1;
+    }
+
+  root = json_parser_get_root (parser);
+  array = json_node_get_array (root);
+  length = json_array_get_length (array);
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(aus)"));
+  i = 0;
+  while (i < length)
+    {
+      JsonNode *node = json_array_get_element (array, i);
+      JsonObject *obj = json_node_get_object (node);
+      GVariantBuilder b1;
+      const char *name;
+      char *code;
+      int j;
+      gboolean skip;
+      gboolean has_variations;
+
+      i++;
+
+      g_variant_builder_init (&b1, G_VARIANT_TYPE ("au"));
+
+      name = json_object_get_string_member (obj, "name");
+      code = g_strdup (json_object_get_string_member (obj, "code"));
+
+      if (strcmp (name, "world map") == 0)
+        continue;
+
+      skip = FALSE;
+      for (j = 0; blacklist[j]; j++)
+        {
+          if (strstr (name, blacklist[j]) != 0)
+            skip = TRUE;
         }
-
-        parser = json_parser_new ();
-
-        if (!json_parser_load_from_file (parser, argv[1], &error)) {
-                g_error ("%s", error->message);
-                return 1;
+      if (skip)
+        continue;
+
+      has_variations = FALSE;
+      while (i < length)
+        {
+          JsonNode *node2 = json_array_get_element (array, i);
+          JsonObject *obj2 = json_node_get_object (node2);
+          const char *name2;
+          const char *code2;
+
+          name2 = json_object_get_string_member (obj2, "name");
+          code2 = json_object_get_string_member (obj2, "code");
+
+          if (!strstr (name2, "skin tone") || !g_str_has_prefix (name2, name))
+            break;
+
+          if (!has_variations)
+            {
+              has_variations = TRUE;
+              g_free (code);
+              code = g_strdup (code2);
+            }
+          i++;
         }
 
-        root = json_parser_get_root (parser);
-        array = json_node_get_array (root);
-        length = json_array_get_length (array);
-
-        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ausaau)"));
-        i = 0;
-        while (i < length) {
-                JsonNode *node = json_array_get_element (array, i);
-                JsonObject *obj = json_node_get_object (node);
-                GVariantBuilder b1, b2;
-                const char *name;
-                const char *code;
-                int j;
-                gboolean skip;
-
-                i++;
-
-                g_variant_builder_init (&b1, G_VARIANT_TYPE ("au"));
-                g_variant_builder_init (&b2, G_VARIANT_TYPE ("aau"));
-
-                name = json_object_get_string_member (obj, "name");
-                code = json_object_get_string_member (obj, "code");
-
-                if (strcmp (name, "world map") == 0)
-                        continue;
-
-                skip = FALSE;
-                for (j = 0; blacklist[j]; j++) {
-                        if (strstr (name, blacklist[j]) != 0) {
-                                skip = TRUE;
-                                break;
-                       }
-                }
-                if (skip)
-                        continue;
-
-                if (!parse_code (&b1, code))
-                        return 1;
-
-                while (i < length) {
-                        JsonNode *node2 = json_array_get_element (array, i);
-                        JsonObject *obj2 = json_node_get_object (node2);
-                        const char *name2;
-                        const char *code2;
-                        GVariantBuilder b22;
-
-                        name2 = json_object_get_string_member (obj2, "name");
-                        code2 = json_object_get_string_member (obj2, "code");
-
-                        if (!strstr (name2, "skin tone") || !g_str_has_prefix (name2, name))
-                                break;
-
-                        g_variant_builder_init (&b22, G_VARIANT_TYPE ("au"));
-                        if (!parse_code (&b22, code2))
-                                return 1;
-
-                        g_variant_builder_add (&b2, "au", &b22);
-                        i++;
-                }
-
-                g_variant_builder_add (&builder, "(ausaau)", &b1, name, &b2);
-        }
+      if (!parse_code (&b1, code))
+        return 1;
 
-        v = g_variant_builder_end (&builder);
-        bytes = g_variant_get_data_as_bytes (v);
-        if (!g_file_set_contents (argv[2], g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), 
&error)) {
-                g_error ("%s", error->message);
-                return 1;
-        }
+      g_variant_builder_add (&builder, "(aus)", &b1, name);
+    }
+
+  v = g_variant_builder_end (&builder);
+  bytes = g_variant_get_data_as_bytes (v);
+  if (!g_file_set_contents (argv[2], g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), &error))
+    {
+      g_error ("%s", error->message);
+      return 1;
+    }
 
-        return 0;
+  return 0;
 }
diff --git a/gtk/emoji/emoji.data b/gtk/emoji/emoji.data
index 61d1af0..12db9d4 100644
Binary files a/gtk/emoji/emoji.data and b/gtk/emoji/emoji.data differ
diff --git a/gtk/gtkemojichooser.c b/gtk/gtkemojichooser.c
index 1da725d..1bd5318 100644
--- a/gtk/gtkemojichooser.c
+++ b/gtk/gtkemojichooser.c
@@ -137,36 +137,55 @@ scroll_to_section (GtkButton *button,
 static void
 add_emoji (GtkWidget    *box,
            gboolean      prepend,
-           GVariantIter *iter,
-           GVariant     *data);
+           GVariant     *item,
+           gunichar      modifier);
 
 #define MAX_RECENT (7*3)
 
 static void
+populate_recent_section (GtkEmojiChooser *chooser)
+{
+  GVariant *variant;
+  GVariant *item;
+  GVariantIter iter;
+
+  variant = g_settings_get_value (chooser->settings, "recent-emoji");
+  g_variant_iter_init (&iter, variant);
+  while ((item = g_variant_iter_next_value (&iter)))
+    {
+      GVariant *emoji_data;
+      gunichar modifier;
+
+      emoji_data = g_variant_get_child_value (item, 0);
+      g_variant_get_child (item, 1, "u", &modifier);
+      add_emoji (chooser->recent.box, FALSE, emoji_data, modifier);
+      g_variant_unref (emoji_data);
+      g_variant_unref (item);
+    }
+  g_variant_unref (variant);
+}
+
+static void
 add_recent_item (GtkEmojiChooser *chooser,
-                 GVariant       *item)
+                 GVariant        *item,
+                 gunichar         modifier)
 {
   GList *children, *l;
-  GVariantIter *codes;
-  const char *name;
   int i;
   GVariantBuilder builder;
 
   g_variant_ref (item);
 
-  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ausaau)"));
-  g_variant_builder_add_value (&builder, item);
-
-  g_variant_get_child (item, 1, "&s", &name);
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a((aus)u)"));
+  g_variant_builder_add (&builder, "(@(aus)u)", item, modifier);
 
   children = gtk_container_get_children (GTK_CONTAINER (chooser->recent.box));
   for (l = children, i = 1; l; l = l->next, i++)
     {
       GVariant *item2 = g_object_get_data (G_OBJECT (l->data), "emoji-data");
-      const char *name2;
+      gunichar modifier2 = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (l->data), "modifier"));
 
-      g_variant_get_child (item2, 1, "&s", &name2);
-      if (strcmp (name, name2) == 0)
+      if (modifier == modifier2 && g_variant_equal (item, item2))
         {
           gtk_widget_destroy (GTK_WIDGET (l->data));
           i--;
@@ -178,13 +197,11 @@ add_recent_item (GtkEmojiChooser *chooser,
           continue;
         }
 
-      g_variant_builder_add_value (&builder, item2);
+      g_variant_builder_add (&builder, "(@(aus)u)", item2, modifier2);
     }
   g_list_free (children);
 
-  g_variant_get_child (item, 0, "au", &codes);
-  add_emoji (chooser->recent.box, TRUE, codes, item);
-  g_variant_iter_free (codes);
+  add_emoji (chooser->recent.box, TRUE, item, modifier);
 
   g_settings_set_value (chooser->settings, "recent-emoji", g_variant_builder_end (&builder));
 
@@ -201,6 +218,7 @@ emoji_activated (GtkFlowBox      *box,
   GtkWidget *ebox;
   GtkWidget *label;
   GVariant *item;
+  gunichar modifier;
 
   gtk_popover_popdown (GTK_POPOVER (chooser));
 
@@ -209,7 +227,8 @@ emoji_activated (GtkFlowBox      *box,
   text = g_strdup (gtk_label_get_label (GTK_LABEL (label)));
 
   item = (GVariant*) g_object_get_data (G_OBJECT (child), "emoji-data");
-  add_recent_item (chooser, item);
+  modifier = (gunichar) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (child), "modifier"));
+  add_recent_item (chooser, item, modifier);
 
   g_signal_emit (data, signals[EMOJI_PICKED], 0, text);
   g_free (text);
@@ -227,8 +246,10 @@ long_pressed_cb (GtkGesture *gesture,
   GtkWidget *box;
   GVariant *emoji_data;
   GtkWidget *parent_popover;
-  GVariantIter *iter;
-  GVariantIter *codes;
+  GVariant *codes;
+  int i;
+  gboolean has_variations;
+  gunichar modifier;
 
   box = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
   child = GTK_WIDGET (gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (box), x, y));
@@ -239,12 +260,21 @@ long_pressed_cb (GtkGesture *gesture,
   if (!emoji_data)
     return;
 
-  g_variant_get_child (emoji_data, 2, "aau", &iter);
-  if (g_variant_iter_n_children (iter) == 0)
+  has_variations = FALSE;
+  codes = g_variant_get_child_value (emoji_data, 0);
+  for (i = 0; i < g_variant_n_children (codes); i++)
     {
-      g_variant_iter_free (iter);
-      return;
+      gunichar code;
+      g_variant_get_child (codes, i, "u", &code);
+      if (code == 0)
+        {
+          has_variations = TRUE;
+          break;
+        }
     }
+  g_variant_unref (codes);
+  if (!has_variations)
+    return;
 
   parent_popover = gtk_widget_get_ancestor (child, GTK_TYPE_POPOVER);
   popover = gtk_popover_new (child);
@@ -261,13 +291,11 @@ long_pressed_cb (GtkGesture *gesture,
 
   g_signal_connect (box, "child-activated", G_CALLBACK (emoji_activated), parent_popover);
 
-  g_variant_get_child (emoji_data, 0, "au", &codes);
-  add_emoji (box, FALSE, codes, emoji_data);
-  g_variant_iter_free (codes);
-  while (g_variant_iter_next (iter, "au", &codes))
+  add_emoji (box, FALSE, emoji_data, 0);
+  for (modifier = 0x1f3fb; modifier <= 0x1f3ff; modifier++)
     {
-      add_emoji (box, FALSE, codes, emoji_data);
-      g_variant_iter_free (codes);
+      add_emoji (box, FALSE, emoji_data, modifier);
+      g_variant_unref (codes);
     }
 
   gtk_widget_show_all (view);
@@ -288,20 +316,30 @@ update_hover (GtkWidget *widget,
 static void
 add_emoji (GtkWidget    *box,
            gboolean      prepend,
-           GVariantIter *iter,
-           GVariant     *data)
+           GVariant     *item,
+           gunichar      modifier)
 {
   GtkWidget *child;
   GtkWidget *ebox;
   GtkWidget *label;
   PangoAttrList *attrs;
+  GVariant *codes;
   char text[64];
   char *p = text;
-  gunichar code;
+  int i;
 
-  while (g_variant_iter_next (iter, "u", &code))
-    p += g_unichar_to_utf8 (code, p);
-  p[0] = 0;
+  codes = g_variant_get_child_value (item, 0);
+  for (i = 0; i < g_variant_n_children (codes); i++)
+    {
+      gunichar code;
+
+      g_variant_get_child (codes, i, "u", &code);
+      if (code == 0)
+        code = modifier;
+      if (code != 0)
+        p += g_unichar_to_utf8 (code, p);
+    }
+   p[0] = 0;
 
   label = gtk_label_new (text);
   attrs = pango_attr_list_new ();
@@ -312,8 +350,10 @@ add_emoji (GtkWidget    *box,
   child = gtk_flow_box_child_new ();
   gtk_style_context_add_class (gtk_widget_get_style_context (child), "emoji");
   g_object_set_data_full (G_OBJECT (child), "emoji-data",
-                          g_variant_ref (data),
+                          g_variant_ref (item),
                           (GDestroyNotify)g_variant_unref);
+  if (modifier != 0)
+    g_object_set_data (G_OBJECT (child), "modifier", GUINT_TO_POINTER (modifier));
 
   ebox = gtk_event_box_new ();
   gtk_widget_add_events (ebox, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
@@ -334,16 +374,14 @@ populate_emoji_chooser (GtkEmojiChooser *chooser)
   GtkWidget *box;
 
   bytes = g_resources_lookup_data ("/org/gtk/libgtk/emoji/emoji.data", 0, NULL);
-  chooser->data = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE ("a(ausaau)"), bytes, TRUE));
+  chooser->data = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE ("a(aus)"), bytes, TRUE));
 
   g_variant_iter_init (&iter, chooser->data);
   box = chooser->people.box;
   while ((item = g_variant_iter_next_value (&iter)))
     {
-      GVariantIter *codes;
       const char *name;
 
-      g_variant_get_child (item, 0, "au", &codes);
       g_variant_get_child (item, 1, "&s", &name);
 
       if (strcmp (name, chooser->body.first) == 0)
@@ -363,8 +401,7 @@ populate_emoji_chooser (GtkEmojiChooser *chooser)
       else if (strcmp (name, chooser->flags.first) == 0)
         box = chooser->flags.box;
 
-      add_emoji (box, FALSE, codes, item);
-      g_variant_iter_free (codes);
+      add_emoji (box, FALSE, item, 0);
     }
 }
 
@@ -514,9 +551,8 @@ static void
 gtk_emoji_chooser_init (GtkEmojiChooser *chooser)
 {
   GtkAdjustment *adj;
-  GVariant *variant;
-  GVariantIter iter;
-  GVariant *item;
+
+  chooser->settings = g_settings_new ("org.gtk.Settings.EmojiChooser");
 
   gtk_widget_init_template (GTK_WIDGET (chooser));
 
@@ -544,19 +580,7 @@ gtk_emoji_chooser_init (GtkEmojiChooser *chooser)
   setup_section (chooser, &chooser->flags, "chequered flag", 0x1f3f4);
 
   populate_emoji_chooser (chooser);
-
-  chooser->settings = g_settings_new ("org.gtk.Settings.EmojiChooser");
-  variant = g_settings_get_value (chooser->settings, "recent-emoji");
-  g_variant_iter_init (&iter, variant);
-  while ((item = g_variant_iter_next_value (&iter)))
-    {
-      GVariantIter *codes;
-
-      g_variant_get_child (item, 0, "au", &codes);
-      add_emoji (chooser->recent.box, FALSE, codes, item);
-      g_variant_iter_free (codes);
-    }
-  g_variant_unref (variant);
+  populate_recent_section (chooser);
 }
 
 static void
diff --git a/gtk/org.gtk.Settings.EmojiChooser.gschema.xml b/gtk/org.gtk.Settings.EmojiChooser.gschema.xml
index d720275..7105cb2 100644
--- a/gtk/org.gtk.Settings.EmojiChooser.gschema.xml
+++ b/gtk/org.gtk.Settings.EmojiChooser.gschema.xml
@@ -2,13 +2,14 @@
 <schemalist>
 
   <schema id='org.gtk.Settings.EmojiChooser' path='/org/gtk/settings/emoji-chooser/'>
-    <key name='recent-emoji' type='a(ausaau)'>
+    <key name='recent-emoji' type='a((aus)u)'>
       <default>[]</default>
       <summary>Recently used Emoji</summary>
       <description>
         An array of Emoji definitions to show in the Emoji chooser. Each Emoji is
-        specified as an array of codepoints, a name, and an optional array of
-        nested Emoji.
+        specified as an array of codepoints and a name. The extra integer after this
+        pair is the code of the Fitzpatrick modifier to use in place of a 0 in the
+        codepoint array.
       </description>
     </key>
   </schema>


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