mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-10 12:40:10 +00:00
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.
This commit is contained in:
parent
f27d928e33
commit
c56545f721
@ -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;
|
||||
g_auto(GStrv) strv = NULL;
|
||||
int j;
|
||||
|
||||
strv = g_strsplit (code, " ", -1);
|
||||
for (j = 0; strv[j]; j++) {
|
||||
guint32 u;
|
||||
char *end;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
|
||||
parser = json_parser_new ();
|
||||
if (!parse_code (&b1, code))
|
||||
return 1;
|
||||
|
||||
if (!json_parser_load_from_file (parser, argv[1], &error)) {
|
||||
g_error ("%s", error->message);
|
||||
return 1;
|
||||
}
|
||||
g_variant_builder_add (&builder, "(aus)", &b1, name);
|
||||
}
|
||||
|
||||
root = json_parser_get_root (parser);
|
||||
array = json_node_get_array (root);
|
||||
length = json_array_get_length (array);
|
||||
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_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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
Binary file not shown.
@ -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
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user