From 800c4039597b0f01d01c31f3031f87c0f660a0ec Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Aug 05 2016 06:20:04 +0000 Subject: Delete ibus-HEAD.patch to bump tarball --- diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch deleted file mode 100644 index 89a27b3..0000000 --- a/ibus-HEAD.patch +++ /dev/null @@ -1,3695 +0,0 @@ -From 0432aa66b8728bc266da3c2cca84587bc44b3557 Mon Sep 17 00:00:00 2001 -From: Matthias Clasen -Date: Tue, 8 Mar 2016 11:16:24 +0900 -Subject: [PATCH] Don't warn if DISPLAY is not set - -This is normal under Wayland, and not worth warning about. -The warnings disrupt unit tests in GNOME continuous, which -treat warnings as fatal. - -BUG=https://github.com/ibus/ibus/pull/1844 -R=shawn.p.huang@gmail.com - -Review URL: https://codereview.appspot.com/289430043 - -Patch from Matthias Clasen . ---- - src/ibusshare.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/src/ibusshare.c b/src/ibusshare.c -index 63800a6..b793a96 100644 ---- a/src/ibusshare.c -+++ b/src/ibusshare.c -@@ -113,10 +113,7 @@ ibus_get_socket_path (void) - display = g_strdup (_display); - } - -- if (display == NULL) { -- g_warning ("DISPLAY is empty! We use default DISPLAY (:0.0)"); -- } -- else { -+ if (display) { - p = display; - hostname = display; - for (; *p != ':' && *p != '\0'; p++); --- -2.7.4 - -From 84c18f1d382548c52138822a11473d2dac79e485 Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Wed, 25 May 2016 11:21:09 +0900 -Subject: [PATCH] Install a DBus service file - -With the transition to user scoped DBus sessions (vs. login sessions) -there's a need to start ibus-daemon via DBus activation so that the -process gets properly tracked and disposed of when the login session -ends. Otherwise the ibus-daemon process lingers on and keeps the whole -login session up. - -We already connect and own a well known name on DBus. The remaining -missing piece is the DBus service file which we introduce here. - -BUG=https://github.com/ibus/ibus/pull/1853 -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/295340043 - -Patch from Rui Matos . ---- - bus/Makefile.am | 11 +++++++++++ - bus/org.freedesktop.IBus.service.in | 3 +++ - 2 files changed, 14 insertions(+) - create mode 100644 bus/org.freedesktop.IBus.service.in - -diff --git a/bus/Makefile.am b/bus/Makefile.am -index 26cb2f8..4dabacf 100644 ---- a/bus/Makefile.am -+++ b/bus/Makefile.am -@@ -174,4 +174,15 @@ man_onedir = $(mandir)/man1 - %.1.gz: %.1 - $(AM_V_GEN) gzip -c $< > $@.tmp && mv $@.tmp $@ - -+ -+dbusservice_in_files = org.freedesktop.IBus.service.in -+dbusservice_DATA = $(dbusservice_in_files:.service.in=.service) -+dbusservicedir=${datadir}/dbus-1/services -+ -+org.freedesktop.IBus.service: org.freedesktop.IBus.service.in -+ $(AM_V_GEN) sed -e "s|\@bindir\@|$(bindir)|" $< > $@.tmp && mv $@.tmp $@ -+ -+EXTRA_DIST += $(dbusservice_in_files) -+CLEANFILES += $(dbusservice_DATA) -+ - -include $(top_srcdir)/git.mk -diff --git a/bus/org.freedesktop.IBus.service.in b/bus/org.freedesktop.IBus.service.in -new file mode 100644 -index 0000000..cc88834 ---- /dev/null -+++ b/bus/org.freedesktop.IBus.service.in -@@ -0,0 +1,3 @@ -+[D-BUS Service] -+Name=org.freedesktop.IBus -+Exec=@bindir@/ibus-daemon --replace --xim --panel disable --- -2.7.4 - -From 3ef21fef0135f7b4fe9611d201f15611734f6c51 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 3 Jun 2016 11:52:29 +0900 -Subject: [PATCH] client/gtk2: Fix SEGV with Wayland display - -Delete gdk_display_get_name() in GTK clients because ibus-daemon -does not use gdk_display_get_name(). -GdkX11Dislay and GdkX11Window does not work with Wayland. - -BUG=https://github.com/ibus/ibus/issues/1859 -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/301760043 ---- - client/gtk2/ibusimcontext.c | 5 ----- - setup/main.py | 7 +++++-- - 2 files changed, 5 insertions(+), 7 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index 9d927e6..0df0062 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -583,11 +583,6 @@ ibus_im_context_class_init (IBusIMContextClass *class) - - /* init bus object */ - if (_bus == NULL) { -- const gchar *dname = gdk_display_get_name (gdk_display_get_default ()); -- /* ibus-daemon uses DISPLAY variable. */ -- if (g_strcmp0 (dname, "Wayland") == 0) -- dname = g_getenv ("DISPLAY"); -- ibus_set_display (dname); - _bus = ibus_bus_new_async (); - - /* init the global fake context */ -diff --git a/setup/main.py b/setup/main.py -index 26c2b0f..e1f7a9d 100644 ---- a/setup/main.py -+++ b/setup/main.py -@@ -275,8 +275,11 @@ class Setup(object): - self.__init_general() - - def __gdk_window_set_cb(self, object, pspec): -- str = '%u' % GdkX11.X11Window.get_xid(object.get_window()) -- GLib.setenv('IBUS_SETUP_XID', str, True) -+ window = object.get_window() -+ if type(window) != GdkX11.X11Window: -+ return -+ s = '%u' % GdkX11.X11Window.get_xid(window) -+ GLib.setenv('IBUS_SETUP_XID', s, True) - - def __combobox_notify_active_engine_cb(self, combobox, property): - engine = self.__combobox.get_active_engine() --- -2.7.4 - -From a598ae29223d1ca25e76bf7d7de9703f63ea337e Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 3 Jun 2016 19:44:11 +0900 -Subject: [PATCH] ui/gtk3: Fix panel CSS format for GTK 3.20 - -CSS node names have been changed since GTK 3.20 and the font size and -widget color no longer work with the previous node names. - -BUG=https://github.com/ibus/ibus/issues/1856 - -Review URL: https://codereview.appspot.com/297380043 ---- - ui/gtk3/candidatearea.vala | 16 +++++++++++++--- - ui/gtk3/handle.vala | 10 ++++++++-- - ui/gtk3/panel.vala | 9 +++++++-- - 3 files changed, 28 insertions(+), 7 deletions(-) - -diff --git a/ui/gtk3/candidatearea.vala b/ui/gtk3/candidatearea.vala -index c969312..3848f0d 100644 ---- a/ui/gtk3/candidatearea.vala -+++ b/ui/gtk3/candidatearea.vala -@@ -3,7 +3,7 @@ - * ibus - The Input Bus - * - * Copyright(c) 2011-2015 Peng Huang -- * Copyright(c) 2015 Takao Fujiwara -+ * Copyright(c) 2015-2016 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -31,6 +31,10 @@ class CandidateArea : Gtk.Box { - private uint m_focus_candidate; - private bool m_show_cursor; - -+ private bool m_use_latest_css_format = -+ ((Gtk.MAJOR_VERSION > 3) || -+ (Gtk.MAJOR_VERSION == 3) && (Gtk.MINOR_VERSION >= 20)); -+ - private const string LABELS[] = { - "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", - "9.", "0.", "a.", "b.", "c.", "d.", "e.", "f." -@@ -103,7 +107,8 @@ class CandidateArea : Gtk.Box { - Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(candidates[i]); - if (i == focus_candidate && show_cursor) { - Gtk.StyleContext context = m_candidates[i].get_style_context(); -- Gdk.RGBA color = context.get_color(Gtk.StateFlags.SELECTED); -+ Gdk.RGBA *color = null; -+ context.get(Gtk.StateFlags.SELECTED, "color", out color); - Pango.Attribute pango_attr = Pango.attr_foreground_new( - (uint16)(color.red * uint16.MAX), - (uint16)(color.green * uint16.MAX), -@@ -112,7 +117,12 @@ class CandidateArea : Gtk.Box { - pango_attr.end_index = candidates[i].get_text().length; - attrs.insert((owned)pango_attr); - -- color = context.get_background_color(Gtk.StateFlags.SELECTED); -+ color = null; -+ string bg_prop = -+ m_use_latest_css_format -+ ? "-gtk-secondary-caret-color" -+ : "background-color"; -+ context.get(Gtk.StateFlags.SELECTED, bg_prop, out color); - pango_attr = Pango.attr_background_new( - (uint16)(color.red * uint16.MAX), - (uint16)(color.green * uint16.MAX), -diff --git a/ui/gtk3/handle.vala b/ui/gtk3/handle.vala -index 1edb537..bef5e8b 100644 ---- a/ui/gtk3/handle.vala -+++ b/ui/gtk3/handle.vala -@@ -2,7 +2,8 @@ - * - * ibus - The Input Bus - * -- * Copyright(c) 2011-2015 Peng Huang -+ * Copyright(c) 2011-2016 Peng Huang -+ * Copyright(c) 2016 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -29,6 +30,11 @@ class Handle : Gtk.EventBox { - public signal void move_end(); - - public Handle() { -+ // Call base class constructor -+ GLib.Object( -+ name : "IBusHandle" -+ ); -+ - set_size_request(6, -1); - Gdk.EventMask mask = Gdk.EventMask.EXPOSURE_MASK | - Gdk.EventMask.BUTTON_PRESS_MASK | -@@ -42,7 +48,7 @@ class Handle : Gtk.EventBox { - Gtk.CssProvider css_provider = new Gtk.CssProvider(); - try { - css_provider.load_from_data( -- "GtkEventBox { background-color: gray }", -1); -+ "#IBusHandle { background-color: gray }", -1); - } catch (GLib.Error error) { - warning("Parse error in Handle: %s", error.message); - } -diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala -index 2ca3a5e..cc19350 100644 ---- a/ui/gtk3/panel.vala -+++ b/ui/gtk3/panel.vala -@@ -3,7 +3,7 @@ - * ibus - The Input Bus - * - * Copyright(c) 2011-2014 Peng Huang -- * Copyright(c) 2015 Takao Fujwiara -+ * Copyright(c) 2015-2016 Takao Fujwiara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -543,7 +543,12 @@ class Panel : IBus.PanelService { - return; - } - -- string data_format = "GtkLabel { font: %s; }"; -+ string data_format = "label { font: %s; }"; -+ if (Gtk.MAJOR_VERSION < 3 || -+ (Gtk.MAJOR_VERSION == 3 && Gtk.MINOR_VERSION < 20)) { -+ data_format = "GtkLabel { font: %s; }"; -+ } -+ - string data = data_format.printf(font_name); - m_css_provider = new Gtk.CssProvider(); - --- -2.7.4 - -From 160d3c975af91eea6b8271b757be769b8ceef98d Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 21 Jun 2016 18:10:21 +0900 -Subject: [PATCH 1/4] engine: Implement Emoji typing with XKB engines - -Now Ctrl+Shift+e can convert an Emoji annotation to the Emoji characters -likes Ctrl+Shift+u. -The annotations are described as "Keywords" in the Unicode Emoji Data: -http://www.unicode.org/emoji/charts/emoji-list.html -'emoji-parser' compiles 'emoji-list.html' and generates 'emoji.dict' - -Review URL: https://codereview.appspot.com/295610043 ---- - configure.ac | 16 ++ - src/Makefile.am | 31 ++++ - src/emoji-parser.c | 217 ++++++++++++++++++++++++ - src/ibusenginesimple.c | 443 ++++++++++++++++++++++++++++++++++++++++++++----- - src/ibusutil.c | 193 ++++++++++++++++++++- - src/ibusutil.h | 31 +++- - 6 files changed, 890 insertions(+), 41 deletions(-) - create mode 100644 src/emoji-parser.c - -diff --git a/configure.ac b/configure.ac -index 1e1f5dd..3128ef9 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -599,6 +599,21 @@ if test x"$enable_libnotify" = x"yes"; then - enable_libnotify="yes (enabled, use --disable-libnotify to disable)" - fi - -+# --disable-emoji-dict option. -+AC_ARG_ENABLE(emoji-dict, -+ AS_HELP_STRING([--disable-emoji-dict], -+ [Do not build Emoji dict files]), -+ [enable_emoji_dict=$enableval], -+ [enable_emoji_dict=yes] -+) -+AM_CONDITIONAL([ENABLE_EMOJI_DICT], [test x"$enable_emoji_dict" = x"yes"]) -+if test x"$enable_emoji_dict" = x"yes"; then -+ PKG_CHECK_MODULES(LIBXML2, [ -+ libxml-2.0 -+ ]) -+ enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)" -+fi -+ - # Check iso-codes. - PKG_CHECK_MODULES(ISOCODES, [ - iso-codes -@@ -682,6 +697,7 @@ Build options: - Panel icon "$IBUS_ICON_KEYBOARD" - Enable surrounding-text $enable_surrounding_text - Enable libnotify $enable_libnotify -+ Enable Emoji dict $enable_emoji_dict - Run test cases $enable_tests - ]) - -diff --git a/src/Makefile.am b/src/Makefile.am -index adaebe9..a33b67d 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -231,7 +231,38 @@ ibusmarshalers.c: ibusmarshalers.h ibusmarshalers.list - $(GLIB_GENMARSHAL) --prefix=_ibus_marshal $(srcdir)/ibusmarshalers.list --body --internal) > $@.tmp && \ - mv $@.tmp $@ - -+if ENABLE_EMOJI_DICT -+AM_CPPFLAGS += -DENABLE_EMOJI_DICT -+ -+dictdir = $(pkgdatadir)/dicts -+dict_DATA = emoji.dict -+ -+noinst_PROGRAMS = emoji-parser -+ -+emoji.dict: emoji-parser emoji-list.html -+ $(builddir)/emoji-parser emoji-list.html $@ -+ -+emoji_parser_SOURCES = \ -+ emoji-parser.c \ -+ $(NULL) -+emoji_parser_CFLAGS = \ -+ $(GLIB2_CFLAGS) \ -+ $(LIBXML2_CFLAGS) \ -+ $(NULL) -+emoji_parser_LDADD = \ -+ $(GLIB2_LIBS) \ -+ $(LIBXML2_LIBS) \ -+ $(libibus) \ -+ $(NULL) -+ -+CLEANFILES += \ -+ $(dict_DATA) \ -+ $(NULL) -+endif -+ - EXTRA_DIST = \ -+ emoji-list.html \ -+ emoji-parser.c \ - ibusversion.h.in \ - ibusmarshalers.list \ - ibusenumtypes.h.template \ -diff --git a/src/emoji-parser.c b/src/emoji-parser.c -new file mode 100644 -index 0000000..cf92fee ---- /dev/null -+++ b/src/emoji-parser.c -@@ -0,0 +1,217 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* ibus - The Input Bus -+ * Copyright (C) 2016 Takao Fujiwara -+ * Copyright (C) 2016 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+/* Convert http://www.unicode.org/emoji/charts/emoji-list.html -+ * to the dictionary file which look up the Emoji from the annotation. -+ */ -+ -+#include -+#include -+#include -+ -+#include "ibusutil.h" -+ -+typedef struct _EmojiData EmojiData; -+struct _EmojiData { -+ gchar *class; -+ gchar *emoji; -+ GSList *annotates; -+ GSList *prev_annotates; -+ GHashTable *dict; -+}; -+ -+const gchar *progname; -+ -+static gboolean parse_node (xmlNode *node, -+ gboolean is_child, -+ const gchar *prop_name, -+ EmojiData *data); -+ -+static void -+usage (void) -+{ -+ g_print ("%s emoji-list.html emoji.dict\n", progname); -+} -+ -+static void -+reset_emoji_element (EmojiData *data) -+{ -+ g_clear_pointer (&data->class, g_free); -+ g_clear_pointer (&data->emoji, g_free); -+ if (data->annotates) { -+ g_slist_free_full (data->prev_annotates, g_free); -+ data->prev_annotates = data->annotates; -+ data->annotates = NULL; -+ } -+} -+ -+static void -+free_dict_words (gpointer list) -+{ -+ g_slist_free_full (list, g_free); -+} -+ -+static gboolean -+parse_attr (xmlAttr *attr, -+ EmojiData *data) -+{ -+ if (g_strcmp0 ((const gchar *) attr->name, "class") == 0 && attr->children) -+ parse_node (attr->children, TRUE, (const gchar *) attr->name, data); -+ if (g_strcmp0 ((const gchar *) attr->name, "target") == 0 && attr->children) -+ parse_node (attr->children, TRUE, (const gchar *) attr->name, data); -+ if (attr->next) -+ parse_attr (attr->next, data); -+ return TRUE; -+} -+ -+static gboolean -+parse_node (xmlNode *node, -+ gboolean is_child, -+ const gchar *prop_name, -+ EmojiData *data) -+{ -+ if (g_strcmp0 ((const gchar *) node->name, "tr") == 0) { -+ GSList *annotates = data->annotates; -+ while (annotates) { -+ GSList *emojis = g_hash_table_lookup (data->dict, annotates->data); -+ if (emojis) { -+ emojis = g_slist_copy_deep (emojis, (GCopyFunc) g_strdup, NULL); -+ } -+ emojis = g_slist_append (emojis, g_strdup (data->emoji)); -+ g_hash_table_replace (data->dict, -+ g_strdup (annotates->data), -+ emojis); -+ annotates = annotates->next; -+ } -+ reset_emoji_element (data); -+ } -+ /* if node->name is "text" and is_child is FALSE, -+ * it's '\n' or Space between and . -+ */ -+ if (g_strcmp0 ((const gchar *) node->name, "text") == 0 && is_child) { -+ /* Get "chars" in */ -+ if (g_strcmp0 (prop_name, "class") == 0) { -+ if (g_strcmp0 (data->class, (const gchar *) node->content) != 0) { -+ g_clear_pointer (&data->class, g_free); -+ data->class = g_strdup ((const gchar *) node->content); -+ } -+ } -+ /* Get "annotate" in */ -+ if (g_strcmp0 (prop_name, "target") == 0 && -+ g_strcmp0 (data->class, "name") == 0) { -+ g_clear_pointer (&data->class, g_free); -+ data->class = g_strdup ((const gchar *) node->content); -+ } -+ /* Get "emoji" in emoji */ -+ if (g_strcmp0 (prop_name, "td") == 0 && -+ g_strcmp0 (data->class, "chars") == 0) { -+ data->emoji = g_strdup ((const gchar *) node->content); -+ } -+ /* We ignore "NAME" for NAME but -+ * takes "ANNOTATE" for -+ * ANNOTATE -+ */ -+ if (g_strcmp0 (prop_name, "td") == 0 && -+ g_strcmp0 (data->class, "name") == 0) { -+ g_slist_free_full (data->annotates, g_free); -+ data->annotates = NULL; -+ } -+ /* Get "ANNOTATE" in -+ * ANNOTATE -+ */ -+ if (g_strcmp0 (prop_name, "a") == 0 && -+ g_strcmp0 (data->class, "annotate") == 0) { -+ data->annotates = -+ g_slist_append (data->annotates, -+ g_strdup ((const gchar *) node->content)); -+ } -+ } -+ /* Get "foo" in */ -+ if (g_strcmp0 ((const gchar *) node->name, "td") == 0 && -+ node->properties != NULL) { -+ parse_attr (node->properties, data); -+ } -+ /* Get "foo" in */ -+ if (g_strcmp0 ((const gchar *) node->name, "a") == 0 && -+ node->properties != NULL) { -+ parse_attr (node->properties, data); -+ } -+ if (node->children) { -+ parse_node (node->children, TRUE, (const gchar *) node->name, data); -+ } else { -+ /* If annotate is NULL likes , -+ * the previous emoji cell has the same annotate. -+ */ -+ if (g_strcmp0 ((const gchar *) node->name, "td") == 0 && -+ g_strcmp0 (data->class, "name") == 0) { -+ data->annotates = g_slist_copy_deep (data->prev_annotates, -+ (GCopyFunc) g_strdup, -+ NULL); -+ } -+ } -+ if (node->next) -+ parse_node (node->next, FALSE, (const gchar *) node->name, data); -+ -+ return TRUE; -+} -+ -+static GHashTable * -+parse_html (const gchar *filename) -+{ -+ xmlDoc *doc = htmlParseFile (filename, "utf-8"); -+ EmojiData data = { 0, }; -+ -+ if (doc == NULL || doc->children == NULL) { -+ g_warning ("Parse Error in document type: %x", -+ doc ? doc->type : 0); -+ return FALSE; -+ } -+ -+ data.dict = g_hash_table_new_full (g_str_hash, -+ g_str_equal, -+ g_free, -+ free_dict_words); -+ parse_node (doc->children, TRUE, (const gchar *) doc->name, &data); -+ -+ reset_emoji_element (&data); -+ g_slist_free_full (data.prev_annotates, g_free); -+ -+ return data.dict; -+} -+ -+int -+main (int argc, char *argv[]) -+{ -+ GHashTable *dict; -+ progname = basename (argv[0]); -+ -+ if (argc < 3) { -+ usage (); -+ return -1; -+ } -+ -+ dict = parse_html (argv[1]); -+ ibus_emoji_dict_save (argv[2], dict); -+ g_hash_table_destroy (dict); -+ -+ return 0; -+} -diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c -index 1b688b0..8efe5a9 100644 ---- a/src/ibusenginesimple.c -+++ b/src/ibusenginesimple.c -@@ -3,7 +3,7 @@ - /* ibus - The Input Bus - * Copyright (C) 2014 Peng Huang - * Copyright (C) 2015-2016 Takao Fujiwara -- * Copyright (C) 2014 Red Hat, Inc. -+ * Copyright (C) 2014-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -31,6 +31,7 @@ - - #include "ibuskeys.h" - #include "ibuskeysyms.h" -+#include "ibusutil.h" - - /* This file contains the table of the compose sequences, - * static const guint16 gtk_compose_seqs_compact[] = {} -@@ -42,16 +43,27 @@ - #include - - #define X11_DATADIR X11_DATA_PREFIX "/share/X11/locale" -+#define EMOJI_SOURCE_LEN 100 - #define IBUS_ENGINE_SIMPLE_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE_SIMPLE, IBusEngineSimplePrivate)) - --struct _IBusEngineSimplePrivate { -- guint16 compose_buffer[IBUS_MAX_COMPOSE_LEN + 1]; -- gunichar tentative_match; -- gint tentative_match_len; -+typedef struct { -+ GHashTable *dict; -+ int max_seq_len; -+} IBusEngineDict; - -- guint in_hex_sequence : 1; -- guint modifiers_dropped : 1; -+struct _IBusEngineSimplePrivate { -+ guint16 compose_buffer[EMOJI_SOURCE_LEN]; -+ gunichar tentative_match; -+ gchar *tentative_emoji; -+ gint tentative_match_len; -+ -+ guint in_hex_sequence : 1; -+ guint in_emoji_sequence : 1; -+ guint modifiers_dropped : 1; -+ IBusEngineDict *emoji_dict; -+ IBusLookupTable *lookup_table; -+ gboolean lookup_table_visible; - }; - - /* From the values below, the value 30 means the number of different first keysyms -@@ -97,6 +109,8 @@ static gboolean ibus_engine_simple_process_key_event - guint modifiers); - static void ibus_engine_simple_commit_char (IBusEngineSimple *simple, - gunichar ch); -+static void ibus_engine_simple_commit_str (IBusEngineSimple *simple, -+ const gchar *str); - static void ibus_engine_simple_update_preedit_text - (IBusEngineSimple *simple); - -@@ -128,6 +142,18 @@ ibus_engine_simple_init (IBusEngineSimple *simple) - static void - ibus_engine_simple_destroy (IBusEngineSimple *simple) - { -+ IBusEngineSimplePrivate *priv = simple->priv; -+ -+ if (priv->emoji_dict) { -+ if (priv->emoji_dict->dict) -+ g_clear_pointer (&priv->emoji_dict->dict, g_hash_table_destroy); -+ g_slice_free (IBusEngineDict, priv->emoji_dict); -+ priv->emoji_dict = NULL; -+ } -+ -+ g_clear_pointer (&priv->lookup_table, g_object_unref); -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ - IBUS_OBJECT_CLASS(ibus_engine_simple_parent_class)->destroy ( - IBUS_OBJECT (simple)); - } -@@ -146,6 +172,11 @@ ibus_engine_simple_reset (IBusEngine *engine) - priv->tentative_match_len = 0; - ibus_engine_hide_preedit_text ((IBusEngine *)simple); - } -+ if (priv->tentative_emoji || priv->in_emoji_sequence) { -+ priv->in_emoji_sequence = FALSE; -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ ibus_engine_hide_preedit_text ((IBusEngine *)simple); -+ } - } - - static void -@@ -162,23 +193,60 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple, - priv->tentative_match_len = 0; - ibus_engine_simple_update_preedit_text (simple); - } -+ if (priv->tentative_emoji || priv->in_emoji_sequence) { -+ priv->in_emoji_sequence = FALSE; -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ ibus_engine_simple_update_preedit_text (simple); -+ } - - ibus_engine_commit_text ((IBusEngine *)simple, - ibus_text_new_from_unichar (ch)); - } - - static void -+ibus_engine_simple_commit_str (IBusEngineSimple *simple, -+ const gchar *str) -+{ -+ IBusEngineSimplePrivate *priv = simple->priv; -+ gchar *backup_str; -+ -+ g_return_if_fail (str && *str); -+ -+ backup_str = g_strdup (str); -+ -+ if (priv->tentative_match || priv->in_hex_sequence) { -+ priv->in_hex_sequence = FALSE; -+ priv->tentative_match = 0; -+ priv->tentative_match_len = 0; -+ ibus_engine_simple_update_preedit_text (simple); -+ } -+ if (priv->tentative_emoji || priv->in_emoji_sequence) { -+ priv->in_emoji_sequence = FALSE; -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ ibus_engine_simple_update_preedit_text (simple); -+ } -+ -+ ibus_engine_commit_text ((IBusEngine *)simple, -+ ibus_text_new_from_string (backup_str)); -+ g_free (backup_str); -+} -+ -+static void - ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - { - IBusEngineSimplePrivate *priv = simple->priv; - -- gunichar outbuf[IBUS_MAX_COMPOSE_LEN + 2]; -+ gunichar outbuf[EMOJI_SOURCE_LEN + 1]; - int len = 0; - -- if (priv->in_hex_sequence) { -+ if (priv->in_hex_sequence || priv->in_emoji_sequence) { - int hexchars = 0; - -- outbuf[0] = L'u'; -+ if (priv->in_hex_sequence) -+ outbuf[0] = L'u'; -+ else -+ outbuf[0] = L'@'; -+ - len = 1; - - while (priv->compose_buffer[hexchars] != 0) { -@@ -187,10 +255,22 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - ++len; - ++hexchars; - } -- g_assert (len <= IBUS_MAX_COMPOSE_LEN + 1); -+ -+ if (priv->in_hex_sequence) -+ g_assert (len <= IBUS_MAX_COMPOSE_LEN + 1); -+ else -+ g_assert (len <= EMOJI_SOURCE_LEN + 1); - } -- else if (priv->tentative_match) -+ else if (priv->tentative_match) { - outbuf[len++] = priv->tentative_match; -+ } else if (priv->tentative_emoji && *priv->tentative_emoji) { -+ IBusText *text = ibus_text_new_from_string (priv->tentative_emoji); -+ len = strlen (priv->tentative_emoji); -+ ibus_text_append_attribute (text, -+ IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, len); -+ ibus_engine_update_preedit_text ((IBusEngine *)simple, text, len, TRUE); -+ return; -+ } - - outbuf[len] = L'\0'; - if (len == 0) { -@@ -277,6 +357,104 @@ check_hex (IBusEngineSimple *simple, - return TRUE; - } - -+static IBusEngineDict * -+load_emoji_dict () -+{ -+ IBusEngineDict *emoji_dict; -+ GList *keys; -+ int max_length = 0; -+ -+ emoji_dict = g_slice_new0 (IBusEngineDict); -+ emoji_dict->dict = ibus_emoji_dict_load (IBUS_DATA_DIR "/dicts/emoji.dict"); -+ if (!emoji_dict->dict) -+ return emoji_dict; -+ -+ keys = g_hash_table_get_keys (emoji_dict->dict); -+ for (; keys; keys = keys->next) { -+ int length = strlen (keys->data); -+ if (max_length < length) -+ max_length = length; -+ } -+ emoji_dict->max_seq_len = max_length; -+ -+ return emoji_dict; -+} -+ -+static gboolean -+check_emoji_table (IBusEngineSimple *simple, -+ gint n_compose, -+ gint index) -+{ -+ IBusEngineSimplePrivate *priv = simple->priv; -+ IBusEngineDict *emoji_dict = priv->emoji_dict; -+ GString *str = NULL; -+ gint i; -+ gchar buf[7]; -+ GSList *words = NULL; -+ -+ g_assert (IBUS_IS_ENGINE_SIMPLE (simple)); -+ -+ if (priv->lookup_table == NULL) { -+ priv->lookup_table = ibus_lookup_table_new (10, 0, TRUE, TRUE); -+ g_object_ref_sink (priv->lookup_table); -+ } -+ if (emoji_dict == NULL) -+ emoji_dict = priv->emoji_dict = load_emoji_dict (simple); -+ -+ if (emoji_dict == NULL || emoji_dict->dict == NULL) -+ return FALSE; -+ -+ if (n_compose > emoji_dict->max_seq_len) -+ return FALSE; -+ -+ str = g_string_new (NULL); -+ priv->lookup_table_visible = FALSE; -+ -+ i = 0; -+ while (i < n_compose) { -+ gunichar ch; -+ -+ ch = ibus_keyval_to_unicode (priv->compose_buffer[i]); -+ -+ if (ch == 0) -+ return FALSE; -+ -+ if (!g_unichar_isprint (ch)) -+ return FALSE; -+ -+ buf[g_unichar_to_utf8 (ch, buf)] = '\0'; -+ -+ g_string_append (str, buf); -+ -+ ++i; -+ } -+ -+ if (str->str) { -+ words = g_hash_table_lookup (emoji_dict->dict, str->str); -+ } -+ g_string_free (str, TRUE); -+ -+ if (words != NULL) { -+ int i = 0; -+ ibus_lookup_table_clear (priv->lookup_table); -+ priv->lookup_table_visible = TRUE; -+ -+ while (words) { -+ if (i == index) { -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ priv->tentative_emoji = g_strdup (words->data); -+ } -+ IBusText *text = ibus_text_new_from_string (words->data); -+ ibus_lookup_table_append_candidate (priv->lookup_table, text); -+ words = words->next; -+ i++; -+ } -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ - static int - compare_seq_index (const void *key, const void *value) - { -@@ -626,10 +804,10 @@ ibus_check_algorithmically (const guint16 *compose_buffer, - - static gboolean - no_sequence_matches (IBusEngineSimple *simple, -- gint n_compose, -- guint keyval, -- guint keycode, -- guint modifiers) -+ gint n_compose, -+ guint keyval, -+ guint keycode, -+ guint modifiers) - { - IBusEngineSimplePrivate *priv = simple->priv; - -@@ -642,8 +820,7 @@ no_sequence_matches (IBusEngineSimple *simple, - gint len = priv->tentative_match_len; - int i; - -- ibus_engine_simple_commit_char (simple, -- priv->tentative_match); -+ ibus_engine_simple_commit_char (simple, priv->tentative_match); - priv->compose_buffer[0] = 0; - - for (i=0; i < n_compose - len - 1; i++) { -@@ -655,8 +832,11 @@ no_sequence_matches (IBusEngineSimple *simple, - - return ibus_engine_simple_process_key_event ( - (IBusEngine *)simple, keyval, keycode, modifiers); -- } -- else { -+ } else if (priv->tentative_emoji && *priv->tentative_emoji) { -+ ibus_engine_simple_commit_str (simple, priv->tentative_emoji); -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ priv->compose_buffer[0] = 0; -+ } else { - priv->compose_buffer[0] = 0; - if (n_compose > 1) { - /* Invalid sequence */ -@@ -676,6 +856,7 @@ no_sequence_matches (IBusEngineSimple *simple, - else - return FALSE; - } -+ return FALSE; - } - - static gboolean -@@ -687,6 +868,39 @@ is_hex_keyval (guint keyval) - } - - static gboolean -+is_graph_keyval (guint keyval) -+{ -+ gunichar ch = ibus_keyval_to_unicode (keyval); -+ -+ return g_unichar_isgraph (ch); -+} -+ -+static void -+ibus_engine_simple_update_lookup_and_aux_table (IBusEngineSimple *simple) -+{ -+ IBusEngineSimplePrivate *priv; -+ guint index, candidates; -+ gchar *aux_label = NULL; -+ IBusText *text = NULL; -+ -+ g_return_if_fail (IBUS_IS_ENGINE_SIMPLE (simple)); -+ -+ priv = simple->priv; -+ index = ibus_lookup_table_get_cursor_pos (priv->lookup_table) + 1; -+ candidates = ibus_lookup_table_get_number_of_candidates(priv->lookup_table); -+ aux_label = g_strdup_printf ("(%u / %u)", index, candidates); -+ text = ibus_text_new_from_string (aux_label); -+ g_free (aux_label); -+ -+ ibus_engine_update_auxiliary_text (IBUS_ENGINE (simple), -+ text, -+ priv->lookup_table_visible); -+ ibus_engine_update_lookup_table (IBUS_ENGINE (simple), -+ priv->lookup_table, -+ priv->lookup_table_visible); -+} -+ -+static gboolean - ibus_engine_simple_process_key_event (IBusEngine *engine, - guint keyval, - guint keycode, -@@ -697,10 +911,13 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - gint n_compose = 0; - gboolean have_hex_mods; - gboolean is_hex_start; -+ gboolean is_emoji_start = FALSE; - gboolean is_hex_end; -+ gboolean is_space; - gboolean is_backspace; - gboolean is_escape; - guint hex_keyval; -+ guint printable_keyval; - gint i; - gboolean compose_finish; - gunichar output_char; -@@ -714,17 +931,16 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - keyval == IBUS_KEY_Shift_L || keyval == IBUS_KEY_Shift_R)) { - if (priv->tentative_match && - g_unichar_validate (priv->tentative_match)) { -- ibus_engine_simple_commit_char (simple, -- priv->tentative_match); -- } -- else if (n_compose == 0) { -+ ibus_engine_simple_commit_char (simple, priv->tentative_match); -+ } else if (n_compose == 0) { - priv->modifiers_dropped = TRUE; -- } -- else { -+ } else { - /* invalid hex sequence */ - /* FIXME beep_window (event->window); */ - priv->tentative_match = 0; -+ g_clear_pointer (&priv->tentative_emoji, g_free); - priv->in_hex_sequence = FALSE; -+ priv->in_emoji_sequence = FALSE; - priv->compose_buffer[0] = 0; - - ibus_engine_simple_update_preedit_text (simple); -@@ -732,6 +948,26 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - - return TRUE; - } -+ /* Handle Shift + Space */ -+ else if (priv->in_emoji_sequence && -+ (keyval == IBUS_KEY_Control_L || keyval == IBUS_KEY_Control_R)) { -+ if (priv->tentative_emoji && *priv->tentative_emoji) { -+ ibus_engine_simple_commit_str (simple, priv->tentative_emoji); -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ } else if (n_compose == 0) { -+ priv->modifiers_dropped = TRUE; -+ } else { -+ /* invalid hex sequence */ -+ /* FIXME beep_window (event->window); */ -+ priv->tentative_match = 0; -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ priv->in_hex_sequence = FALSE; -+ priv->in_emoji_sequence = FALSE; -+ priv->compose_buffer[0] = 0; -+ -+ ibus_engine_simple_update_preedit_text (simple); -+ } -+ } - else - return FALSE; - } -@@ -741,25 +977,33 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - if (keyval == ibus_compose_ignore[i]) - return FALSE; - -- if (priv->in_hex_sequence && priv->modifiers_dropped) -+ if ((priv->in_hex_sequence || priv->in_emoji_sequence) -+ && priv->modifiers_dropped) { - have_hex_mods = TRUE; -- else -+ } else { - have_hex_mods = (modifiers & (HEX_MOD_MASK)) == HEX_MOD_MASK; -+ } - - is_hex_start = keyval == IBUS_KEY_U; -+#ifdef ENABLE_EMOJI_DICT -+ is_emoji_start = keyval == IBUS_KEY_E; -+#endif - is_hex_end = (keyval == IBUS_KEY_space || - keyval == IBUS_KEY_KP_Space || - keyval == IBUS_KEY_Return || - keyval == IBUS_KEY_ISO_Enter || - keyval == IBUS_KEY_KP_Enter); -+ is_space = (keyval == IBUS_KEY_space || keyval == IBUS_KEY_KP_Space); - is_backspace = keyval == IBUS_KEY_BackSpace; - is_escape = keyval == IBUS_KEY_Escape; - hex_keyval = is_hex_keyval (keyval) ? keyval : 0; -+ printable_keyval = is_graph_keyval (keyval) ? keyval : 0; - - /* gtkimcontextsimple causes a buffer overflow in priv->compose_buffer. - * Add the check code here. - */ -- if (n_compose >= IBUS_MAX_COMPOSE_LEN) { -+ if ((n_compose >= IBUS_MAX_COMPOSE_LEN && priv->in_hex_sequence) || -+ (n_compose >= EMOJI_SOURCE_LEN && priv->in_emoji_sequence)) { - if (is_backspace) { - priv->compose_buffer[--n_compose] = 0; - } -@@ -767,7 +1011,9 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - /* invalid hex sequence */ - // beep_window (event->window); - priv->tentative_match = 0; -+ g_clear_pointer (&priv->tentative_emoji, g_free); - priv->in_hex_sequence = FALSE; -+ priv->in_emoji_sequence = FALSE; - priv->compose_buffer[0] = 0; - } - else if (is_escape) { -@@ -789,12 +1035,16 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - * ISO_Level3_Switch. - */ - if (!have_hex_mods || -- (n_compose > 0 && !priv->in_hex_sequence) || -- (n_compose == 0 && !priv->in_hex_sequence && !is_hex_start) || -+ (n_compose > 0 && !priv->in_hex_sequence && !priv->in_emoji_sequence) || -+ (n_compose == 0 && !priv->in_hex_sequence && !is_hex_start && -+ !priv->in_emoji_sequence && !is_emoji_start) || - (priv->in_hex_sequence && !hex_keyval && -- !is_hex_start && !is_hex_end && !is_escape && !is_backspace)) { -+ !is_hex_start && !is_hex_end && !is_escape && !is_backspace) || -+ (priv->in_emoji_sequence && !printable_keyval && -+ !is_emoji_start && !is_hex_end && !is_escape && !is_backspace)) { - if (modifiers & (IBUS_MOD1_MASK | IBUS_CONTROL_MASK) || -- (priv->in_hex_sequence && priv->modifiers_dropped && -+ ((priv->in_hex_sequence || priv->in_emoji_sequence) && -+ priv->modifiers_dropped && - (keyval == IBUS_KEY_Return || - keyval == IBUS_KEY_ISO_Enter || - keyval == IBUS_KEY_KP_Enter))) { -@@ -816,6 +1066,20 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - - return TRUE; - } -+ if (priv->in_emoji_sequence && have_hex_mods && is_backspace) { -+ if (n_compose > 0) { -+ n_compose--; -+ priv->compose_buffer[n_compose] = 0; -+ check_emoji_table (simple, n_compose, -1); -+ ibus_engine_simple_update_lookup_and_aux_table (simple); -+ } else { -+ priv->in_emoji_sequence = FALSE; -+ } -+ -+ ibus_engine_simple_update_preedit_text (simple); -+ -+ return TRUE; -+ } - - /* Check for hex sequence restart */ - if (priv->in_hex_sequence && have_hex_mods && is_hex_start) { -@@ -833,13 +1097,41 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - } - } - } -+ if (priv->in_emoji_sequence && have_hex_mods && is_emoji_start) { -+ if (priv->tentative_emoji && *priv->tentative_emoji) { -+ ibus_engine_simple_commit_str (simple, priv->tentative_emoji); -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ } -+ else { -+ if (n_compose > 0) { -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ priv->in_emoji_sequence = FALSE; -+ priv->compose_buffer[0] = 0; -+ } -+ } -+ } - - /* Check for hex sequence start */ - if (!priv->in_hex_sequence && have_hex_mods && is_hex_start) { - priv->compose_buffer[0] = 0; - priv->in_hex_sequence = TRUE; -+ priv->in_emoji_sequence = FALSE; - priv->modifiers_dropped = FALSE; - priv->tentative_match = 0; -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ -+ // g_debug ("Start HEX MODE"); -+ -+ ibus_engine_simple_update_preedit_text (simple); -+ -+ return TRUE; -+ } else if (!priv->in_emoji_sequence && have_hex_mods && is_emoji_start) { -+ priv->compose_buffer[0] = 0; -+ priv->in_hex_sequence = FALSE; -+ priv->in_emoji_sequence = TRUE; -+ priv->modifiers_dropped = FALSE; -+ priv->tentative_match = 0; -+ g_clear_pointer (&priv->tentative_emoji, g_free); - - // g_debug ("Start HEX MODE"); - -@@ -864,9 +1156,20 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - // beep_window (event->window); - return TRUE; - } -- } -- else -+ } else if (priv->in_emoji_sequence) { -+ if (printable_keyval) { -+ priv->compose_buffer[n_compose++] = printable_keyval; -+ } -+ else if (is_space && (modifiers & IBUS_SHIFT_MASK)) { -+ priv->compose_buffer[n_compose++] = IBUS_KEY_space; -+ } -+ else if (is_escape) { -+ ibus_engine_simple_reset (engine); -+ return TRUE; -+ } -+ } else { - priv->compose_buffer[n_compose++] = keyval; -+ } - - priv->compose_buffer[n_compose] = 0; - -@@ -880,8 +1183,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - ibus_engine_simple_commit_char (simple, - priv->tentative_match); - priv->compose_buffer[0] = 0; -- } -- else { -+ } else { - // FIXME - /* invalid hex sequence */ - // beep_window (event->window); -@@ -899,6 +1201,73 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - return TRUE; - } - } -+ else if (priv->in_emoji_sequence) { -+ if (have_hex_mods && n_compose > 0) { -+ gboolean update_lookup_table = FALSE; -+ -+ if (priv->lookup_table_visible) { -+ switch (keyval) { -+ case IBUS_KEY_space: -+ case IBUS_KEY_KP_Space: -+ if ((modifiers & IBUS_SHIFT_MASK) == 0) { -+ ibus_lookup_table_cursor_down (priv->lookup_table); -+ update_lookup_table = TRUE; -+ } -+ break; -+ case IBUS_KEY_Down: -+ ibus_lookup_table_cursor_down (priv->lookup_table); -+ update_lookup_table = TRUE; -+ break; -+ case IBUS_KEY_Up: -+ ibus_lookup_table_cursor_up (priv->lookup_table); -+ update_lookup_table = TRUE; -+ break; -+ case IBUS_KEY_Page_Down: -+ ibus_lookup_table_page_down (priv->lookup_table); -+ update_lookup_table = TRUE; -+ break; -+ case IBUS_KEY_Page_Up: -+ ibus_lookup_table_page_up (priv->lookup_table); -+ update_lookup_table = TRUE; -+ break; -+ default:; -+ } -+ } -+ -+ if (!update_lookup_table) { -+ if (is_hex_end && !is_space) { -+ if (priv->lookup_table) { -+ int index = (int) ibus_lookup_table_get_cursor_pos ( -+ priv->lookup_table); -+ check_emoji_table (simple, n_compose, index); -+ priv->lookup_table_visible = FALSE; -+ update_lookup_table = TRUE; -+ } -+ } -+ else if (check_emoji_table (simple, n_compose, -1)) { -+ update_lookup_table = TRUE; -+ } -+ } -+ -+ if (update_lookup_table) -+ ibus_engine_simple_update_lookup_and_aux_table (simple); -+ if (is_hex_end && !is_space) { -+ if (priv->tentative_emoji && *priv->tentative_emoji) { -+ ibus_engine_simple_commit_str (simple, -+ priv->tentative_emoji); -+ priv->compose_buffer[0] = 0; -+ } else { -+ g_clear_pointer (&priv->tentative_emoji, g_free); -+ priv->in_emoji_sequence = FALSE; -+ priv->compose_buffer[0] = 0; -+ } -+ } -+ -+ ibus_engine_simple_update_preedit_text (simple); -+ -+ return TRUE; -+ } -+ } - else { - GSList *list = global_tables; - while (list) { -diff --git a/src/ibusutil.c b/src/ibusutil.c -index b9f3fdd..bfaa4f4 100644 ---- a/src/ibusutil.c -+++ b/src/ibusutil.c -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* bus - The Input Bus - * Copyright (C) 2008-2015 Peng Huang -- * Copyright (C) 2010-2015 Takao Fujiwara -- * Copyright (C) 2008-2015 Red Hat, Inc. -+ * Copyright (C) 2010-2016 Takao Fujiwara -+ * Copyright (C) 2008-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -34,6 +34,9 @@ - #include - #endif - -+#define IBUS_DICT_MAGIC "IBusDict" -+#define IBUS_DICT_VERSION (1) -+ - /* gettext macro */ - #define N_(t) t - -@@ -125,6 +128,74 @@ _load_lang() - ibus_xml_free (node); - } - -+static void -+free_dict_words (gpointer list) -+{ -+ g_slist_free_full (list, g_free); -+} -+ -+static void -+variant_foreach_add_emoji (gchar *annotation, -+ GSList *emojis, -+ GVariantBuilder *builder) -+{ -+ int i; -+ int length = (int) g_slist_length (emojis); -+ gchar **buff = g_new0 (gchar *, length); -+ GSList *l = emojis; -+ -+ for (i = 0; i < length; i++, l = l->next) -+ buff[i] = (gchar *) l->data; -+ -+ g_variant_builder_add (builder, -+ "{sv}", -+ annotation, -+ g_variant_new_strv ((const gchar * const *) buff, -+ length)); -+ g_free (buff); -+} -+ -+static GVariant * -+ibus_emoji_dict_serialize (GHashTable *dict) -+{ -+ GVariantBuilder builder; -+ -+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); -+ g_hash_table_foreach (dict, (GHFunc) variant_foreach_add_emoji, &builder); -+ return g_variant_builder_end (&builder); -+} -+ -+static GHashTable * -+ibus_emoji_dict_deserialize (GVariant *variant) -+{ -+ GHashTable *dict = NULL; -+ GVariantIter iter; -+ gchar *annotate = NULL; -+ GVariant *emojis_variant = NULL; -+ -+ dict = g_hash_table_new_full (g_str_hash, -+ g_str_equal, -+ g_free, -+ free_dict_words); -+ -+ g_variant_iter_init (&iter, variant); -+ while (g_variant_iter_loop (&iter, "{sv}", &annotate, &emojis_variant)) { -+ gsize i; -+ gsize length = 0; -+ const gchar **array = g_variant_get_strv (emojis_variant, &length); -+ GSList *emojis = NULL; -+ -+ for (i = 0; i < length; i++) { -+ emojis = g_slist_append (emojis, g_strdup (array[i])); -+ } -+ g_hash_table_insert (dict, annotate, emojis); -+ annotate = NULL; -+ g_clear_pointer (&emojis_variant, g_variant_unref); -+ } -+ -+ return dict; -+} -+ - const gchar * - ibus_get_untranslated_language_name (const gchar *_locale) - { -@@ -171,3 +242,121 @@ ibus_g_variant_get_child_string (GVariant *variant, gsize index, char **str) - g_free (*str); - g_variant_get_child (variant, index, "s", str); - } -+ -+void -+ibus_emoji_dict_save (const gchar *path, GHashTable *dict) -+{ -+ GVariant *variant; -+ const gchar *header = IBUS_DICT_MAGIC; -+ const guint16 version = IBUS_DICT_VERSION; -+ const gchar *contents; -+ gsize length; -+ GError *error = NULL; -+ -+ variant = g_variant_new ("(sqv)", -+ header, -+ version, -+ ibus_emoji_dict_serialize (dict)); -+ -+ contents = g_variant_get_data (variant); -+ length = g_variant_get_size (variant); -+ -+ if (!g_file_set_contents (path, contents, length, &error)) { -+ g_warning ("Failed to save emoji dict %s: %s", path, error->message); -+ g_error_free (error); -+ } -+ -+ g_variant_unref (variant); -+} -+ -+GHashTable * -+ibus_emoji_dict_load (const gchar *path) -+{ -+ gchar *contents = NULL; -+ gsize length = 0; -+ GError *error = NULL; -+ GVariant *variant_table = NULL; -+ GVariant *variant = NULL; -+ const gchar *header = NULL; -+ guint16 version = 0; -+ GHashTable *retval = NULL; -+ -+ if (!g_file_test (path, G_FILE_TEST_EXISTS)) { -+ g_warning ("Emoji dict does not exist: %s", path); -+ goto out_load_cache; -+ } -+ -+ if (!g_file_get_contents (path, &contents, &length, &error)) { -+ g_warning ("Failed to get dict content %s: %s", path, error->message); -+ g_error_free (error); -+ goto out_load_cache; -+ } -+ -+ variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sq)"), -+ contents, -+ length, -+ FALSE, -+ NULL, -+ NULL); -+ -+ if (variant_table == NULL) { -+ g_warning ("cache table is broken."); -+ goto out_load_cache; -+ } -+ -+ g_variant_get (variant_table, "(&sq)", &header, &version); -+ -+ if (g_strcmp0 (header, IBUS_DICT_MAGIC) != 0) { -+ g_warning ("cache is not IBusDict."); -+ goto out_load_cache; -+ } -+ -+ if (version != IBUS_DICT_VERSION) { -+ g_warning ("cache version is different: %u != %u", -+ version, IBUS_DICT_VERSION); -+ goto out_load_cache; -+ } -+ -+ version = 0; -+ header = NULL; -+ g_variant_unref (variant_table); -+ -+ variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sqv)"), -+ contents, -+ length, -+ FALSE, -+ NULL, -+ NULL); -+ -+ if (variant_table == NULL) { -+ g_warning ("cache table is broken."); -+ goto out_load_cache; -+ } -+ -+ g_variant_get (variant_table, "(&sqv)", -+ NULL, -+ NULL, -+ &variant); -+ -+ if (variant == NULL) { -+ g_warning ("cache dict is broken."); -+ goto out_load_cache; -+ } -+ -+ retval = ibus_emoji_dict_deserialize (variant); -+ -+out_load_cache: -+ if (variant) -+ g_variant_unref (variant); -+ if (variant_table) -+ g_variant_unref (variant_table); -+ -+ return retval; -+} -+ -+GSList * -+ibus_emoji_dict_lookup (GHashTable *dict, -+ const gchar *annotation) -+{ -+ return (GSList *) g_hash_table_lookup (dict, annotation); -+} -diff --git a/src/ibusutil.h b/src/ibusutil.h -index 2c1360c..e619b67 100644 ---- a/src/ibusutil.h -+++ b/src/ibusutil.h -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* bus - The Input Bus - * Copyright (C) 2008-2015 Peng Huang -- * Copyright (C) 2010-2015 Takao Fujiwara -- * Copyright (C) 2008-2015 Red Hat, Inc. -+ * Copyright (C) 2010-2016 Takao Fujiwara -+ * Copyright (C) 2008-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -53,4 +53,31 @@ const gchar * ibus_get_untranslated_language_name - */ - const gchar * ibus_get_language_name (const gchar *_locale); - -+/** -+ * ibus_emoji_dict_save: -+ * @path: A path of the saved dictionary file. -+ * @dict: (element-type utf8 gpointer) (transfer none): An Emoji dictionary -+ * -+ * Save the Emoji dictionary to the cache file. -+ */ -+void ibus_emoji_dict_save (const gchar *path, -+ GHashTable *dict); -+/** -+ * ibus_emoji_dict_load: -+ * @path: A path of the saved dictionary file. -+ * -+ * Returns: (element-type utf8 gpointer) (transfer none): An Emoji dictionary file loaded from the saved cache file. -+ */ -+GHashTable * ibus_emoji_dict_load (const gchar *path); -+ -+/** -+ * ibus_emoji_dict_lookup: -+ * @dict: (element-type utf8 gpointer) (transfer none): An Emoji dictionary -+ * @annotation: Annotation for Emoji characters -+ * -+ * Returns: (element-type utf8) (transfer none): List of Emoji characters -+ * This API is for gobject-introspection. -+ */ -+GSList * ibus_emoji_dict_lookup (GHashTable *dict, -+ const gchar *annotation); - #endif --- -2.7.4 - -From 0ed644cd2b6c1d15bdba0d1c6d45d162b9b34806 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Thu, 23 Jun 2016 11:52:48 +0900 -Subject: [PATCH 2/4] engine: Add emoji-list.html - -Now we copied http://unicode.org/emoji/charts/emoji-list.html to -http://ibus.github.io/files/ibus/emoji-list.html -and download the file in the build time. -We don't save emoji-list.html in the tarball because the file size is -more than 5MB. -We always don't get the latest emoji-list.html to avoid the build error. - -BUG=https://github.com/ibus/ibus/pull/1864 -R=shawn.p.huang@gmail.com - -Review URL: https://codereview.appspot.com/298580043 ---- - src/Makefile.am | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/src/Makefile.am b/src/Makefile.am -index a33b67d..22e031f 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -29,6 +29,15 @@ endif - - SUBDIRS = . $(TESTS_DIR) - -+IBUS_V_wget = $(ibus__v_wget_@AM_V@) -+ibus__v_wget_ = $(ibus__v_wget_@AM_DEFAULT_V@) -+ibus__v_wget_0 = -nv -+ibus__v_wget_1 = -+IBUS_V_diff = $(ibus__v_diff_@AM_V@) -+ibus__v_diff_ = $(ibus__v_diff_@AM_DEFAULT_V@) -+ibus__v_diff_0 = -q -+ibus__v_diff_1 = -+ - # libibus = libibus-@IBUS_API_VERSION@.la - libibus = libibus-1.0.la - -@@ -239,6 +248,18 @@ dict_DATA = emoji.dict - - noinst_PROGRAMS = emoji-parser - -+emoji-list.html: -+ $(AM_V_at)wget $(IBUS_V_wget) \ -+ http://ibus.github.io/files/ibus/emoji-list.html -+ $(AM_V_at)wget $(IBUS_V_wget) \ -+ http://unicode.org/emoji/charts/emoji-list.html \ -+ -O latest-emoji-list.html -+ $(AM_V_at)diff $(IBUS_V_diff) emoji-list.html latest-emoji-list.html; \ -+ if test $$? -ne 0; then \ -+ echo "#### WARNING: emoji-list.html is old." >&2; \ -+ fi; \ -+ rm latest-emoji-list.html; -+ - emoji.dict: emoji-parser emoji-list.html - $(builddir)/emoji-parser emoji-list.html $@ - -@@ -257,11 +278,11 @@ emoji_parser_LDADD = \ - - CLEANFILES += \ - $(dict_DATA) \ -+ emoji-list.html \ - $(NULL) - endif - - EXTRA_DIST = \ -- emoji-list.html \ - emoji-parser.c \ - ibusversion.h.in \ - ibusmarshalers.list \ --- -2.7.4 - -From 0ee1896a2b3e75494f8f9fd9d04c27436f0877b8 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Thu, 7 Jul 2016 12:47:34 +0900 -Subject: [PATCH 3/4] engine: Use annotations/en.xml from unocode.org but not - emoji-list.html - -Downloading emoji-list would cause a different build by build site. -Now save annotations/en.xml from unicode.org and get emoji.json from -Emoji One. -en.xml is used for Unicode annotations and emoji.json is used for -aliases_ascii, e.g. ":)", and category, e.g. "people". - -BUG=https://github.com/ibus/ibus/issues/1865 -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/299530044 ---- - COPYING.unicode | 52 +++ - Makefile.am | 1 + - configure.ac | 14 +- - data/Makefile.am | 5 +- - data/annotations/Makefile.am | 27 ++ - data/annotations/en.xml | 1042 ++++++++++++++++++++++++++++++++++++++++++ - ibus.spec.in | 14 + - src/Makefile.am | 31 +- - src/emoji-parser.c | 605 +++++++++++++++++++----- - 9 files changed, 1634 insertions(+), 157 deletions(-) - create mode 100644 COPYING.unicode - create mode 100644 data/annotations/Makefile.am - create mode 100644 data/annotations/en.xml - -diff --git a/COPYING.unicode b/COPYING.unicode -new file mode 100644 -index 0000000..28d3060 ---- /dev/null -+++ b/COPYING.unicode -@@ -0,0 +1,52 @@ -+(Apply to data/annotations/en.xml) -+ -+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE -+ -+ Unicode Data Files include all data files under the directories -+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and -+http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF -+online code charts under the directory http://www.unicode.org/Public/. -+Software includes any source code published in the Unicode Standard or under -+the directories http://www.unicode.org/Public/, -+http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/. -+ -+ NOTICE TO USER: Carefully read the following legal agreement. BY -+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES -+("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND -+AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF -+YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA -+FILES OR SOFTWARE. -+ -+ COPYRIGHT AND PERMISSION NOTICE -+ -+ Copyright ยฉ 1991-2016 Unicode, Inc. All rights reserved. Distributed under -+the Terms of Use in http://www.unicode.org/copyright.html. -+ -+ Permission is hereby granted, free of charge, to any person obtaining a -+copy of the Unicode data files and any associated documentation (the "Data -+Files") or Unicode software and any associated documentation (the "Software") -+to deal in the Data Files or Software without restriction, including without -+limitation the rights to use, copy, modify, merge, publish, distribute, and/or -+sell copies of the Data Files or Software, and to permit persons to whom the -+Data Files or Software are furnished to do so, provided that (a) the above -+copyright notice(s) and this permission notice appear with all copies of the -+Data Files or Software, (b) both the above copyright notice(s) and this -+permission notice appear in associated documentation, and (c) there is clear -+notice in each modified Data File or in the Software as well as in the -+documentation associated with the Data File(s) or Software that the data or -+software has been modified. -+ -+ THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD -+PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN -+THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE -+DATA FILES OR SOFTWARE. -+ -+ Except as contained in this notice, the name of a copyright holder shall -+not be used in advertising or otherwise to promote the sale, use or other -+dealings in these Data Files or Software without prior written authorization -+of the copyright holder. -diff --git a/Makefile.am b/Makefile.am -index 3c4702c..425d1ec 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -69,6 +69,7 @@ pkgconfig_DATA = ibus-@IBUS_API_VERSION@.pc - - ibus_pc_in = ibus-@IBUS_API_VERSION@.pc.in - EXTRA_DIST = \ -+ COPYING.unicode \ - autogen.sh \ - $(ibus_pc_in) \ - ibus.spec.in \ -diff --git a/configure.ac b/configure.ac -index 3128ef9..f789819 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -608,12 +608,20 @@ AC_ARG_ENABLE(emoji-dict, - ) - AM_CONDITIONAL([ENABLE_EMOJI_DICT], [test x"$enable_emoji_dict" = x"yes"]) - if test x"$enable_emoji_dict" = x"yes"; then -- PKG_CHECK_MODULES(LIBXML2, [ -- libxml-2.0 -+ PKG_CHECK_MODULES(JSON_GLIB1, [ -+ json-glib-1.0 - ]) - enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)" - fi - -+AC_ARG_WITH(emoji-json-file, -+ AS_HELP_STRING([--with-emoji-json-file[=DIR/emoji.json]], -+ [Set emoji.json. (default: "/usr/lib/node_modules/emojione/emoji.json")]), -+ EMOJI_JSON_FILE=$with_emoji_json_file, -+ EMOJI_JSON_FILE="/usr/lib/node_modules/emojione/emoji.json" -+) -+AC_SUBST(EMOJI_JSON_FILE) -+ - # Check iso-codes. - PKG_CHECK_MODULES(ISOCODES, [ - iso-codes -@@ -639,6 +647,7 @@ engine/Makefile - util/Makefile - util/IMdkit/Makefile - data/Makefile -+data/annotations/Makefile.am - data/icons/Makefile - data/keymaps/Makefile - data/dconf/Makefile -@@ -698,6 +707,7 @@ Build options: - Enable surrounding-text $enable_surrounding_text - Enable libnotify $enable_libnotify - Enable Emoji dict $enable_emoji_dict -+ emoji.json path $EMOJI_JSON_FILE - Run test cases $enable_tests - ]) - -diff --git a/data/Makefile.am b/data/Makefile.am -index e41c9a2..d9d613f 100644 ---- a/data/Makefile.am -+++ b/data/Makefile.am -@@ -2,8 +2,8 @@ - # - # ibus - The Input Bus - # --# Copyright (c) 2007-2010 Peng Huang --# Copyright (c) 2007-2010 Red Hat, Inc. -+# Copyright (c) 2007-2016 Peng Huang -+# Copyright (c) 2007-2016 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -21,6 +21,7 @@ - # USA - - SUBDIRS = \ -+ annotations \ - icons \ - keymaps \ - $(NULL) -diff --git a/data/annotations/Makefile.am b/data/annotations/Makefile.am -new file mode 100644 -index 0000000..d87b933 ---- /dev/null -+++ b/data/annotations/Makefile.am -@@ -0,0 +1,27 @@ -+# vim:set noet ts=4: -+# -+# ibus - The Input Bus -+# -+# Copyright (c) 2016 Takao Fujiwara -+# Copyright (c) 2016 Red Hat, Inc. -+# -+# This library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2.1 of the License, or (at your option) any later version. -+# -+# This library 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 -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with this library; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+# USA -+ -+EXTRA_DIST = \ -+ en.xml \ -+ $(NULL) -+ -+-include $(top_srcdir)/git.mk -diff --git a/data/annotations/en.xml b/data/annotations/en.xml -new file mode 100644 -index 0000000..ff7aa89 ---- /dev/null -+++ b/data/annotations/en.xml -@@ -0,0 +1,1042 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ face; grin -+ eye; face; grin; smile -+ face; joy; laugh; tear -+ face; mouth; open; smile -+ eye; face; mouth; open; smile -+ cold; face; open; smile; sweat -+ face; laugh; mouth; open; satisfied; smile -+ face; wink -+ blush; eye; face; smile -+ delicious; face; savouring; smile; um; yum -+ bright; cool; eye; eyewear; face; glasses; smile; sun; sunglasses; weather -+ eye; face; heart; love; smile -+ face; heart; kiss -+ face; kiss -+ eye; face; kiss; smile -+ closed; eye; face; kiss -+ face; outlined; relaxed; smile -+ face; smile -+ face; hug; hugging -+ angel; face; fairy tale; fantasy; halo; innocent; smile -+ face; thinking -+ deadpan; face; neutral -+ expressionless; face; inexpressive; unexpressive -+ face; mouth; quiet; silent -+ eyes; face; rolling -+ face; smirk -+ face; persevere -+ disappointed; face; relieved; whew -+ face; mouth; open; sympathy -+ face; mouth; zipper -+ face; hushed; stunned; surprised -+ face; sleep -+ face; tired -+ face; sleep; zzz -+ face; relieved -+ face; geek; nerd -+ face; tongue -+ eye; face; joke; tongue; wink -+ eye; face; horrible; taste; tongue -+ face; frown -+ face; frown -+ face; unamused; unhappy -+ cold; face; sweat -+ dejected; face; pensive -+ confused; face -+ confounded; face -+ face; upside-down -+ cold; doctor; face; mask; medicine; sick -+ face; ill; sick; thermometer -+ bandage; face; hurt; injury -+ face; money; mouth -+ astonished; face; shocked; totally -+ disappointed; face -+ face; worried -+ face; triumph; won -+ cry; face; sad; tear -+ cry; face; sad; sob; tear -+ face; frown; mouth; open -+ anguished; face -+ face; fear; fearful; scared -+ face; tired; weary -+ face; grimace -+ blue; cold; face; mouth; open; rushed; sweat -+ face; fear; fearful; munch; scared; scream -+ dazed; face; flushed -+ dizzy; face -+ angry; face; mad; pouting; rage; red -+ angry; face; mad -+ face; fairy tale; fantasy; horns; smile -+ demon; devil; face; fairy tale; fantasy -+ creature; face; fairy tale; fantasy; japanese; monster -+ creature; face; fairy tale; fantasy; japanese; monster -+ body; death; face; fairy tale; monster -+ body; crossbones; death; face; monster; skull -+ creature; face; fairy tale; fantasy; monster -+ creature; extraterrestrial; face; fairy tale; fantasy; monster; space; ufo -+ alien; creature; extraterrestrial; face; fairy tale; fantasy; monster; space; ufo -+ face; monster; robot -+ comic; dung; face; monster; poo; poop -+ cat; face; mouth; open; smile -+ cat; eye; face; grin; smile -+ cat; face; joy; tear -+ cat; eye; face; heart; love; smile -+ cat; face; ironic; smile; wry -+ cat; eye; face; kiss -+ cat; face; oh; surprised; weary -+ cat; cry; face; sad; tear -+ cat; face; pouting -+ evil; face; forbidden; gesture; monkey; no; not; prohibited; see -+ evil; face; forbidden; gesture; hear; monkey; no; not; prohibited -+ evil; face; forbidden; gesture; monkey; no; not; prohibited; speak -+ boy -+ maiden; virgin; virgo; zodiac -+ man -+ woman -+ man; old -+ old; woman -+ baby -+ blond -+ cop; officer; police -+ gua pi mao; hat; man -+ man; turban -+ construction; hat; worker -+ aid; cross; face; hat; helmet -+ fairy tale; fantasy -+ guard -+ sleuth; spy -+ celebration; christmas; fairy tale; fantasy; father; santa -+ angel; baby; face; fairy tale; fantasy -+ massage; salon -+ barber; beauty; parlor -+ bride; veil; wedding -+ frown; gesture -+ gesture; pouting -+ forbidden; gesture; hand; no; not; prohibited -+ gesture; hand; ok -+ hand; help; information; sassy -+ gesture; hand; happy; raised -+ apology; bow; gesture; sorry -+ body; celebration; gesture; hand; hooray; raised -+ ask; body; bow; folded; gesture; hand; please; pray; thanks -+ face; head; silhouette; speak; speaking -+ bust; silhouette -+ bust; silhouette -+ hike; walk; walking -+ marathon; running -+ bunny; dancer; ear; girl; woman -+ dancer -+ business; man; suit -+ couple; romance -+ couple; heart; love; romance -+ child; father; mother -+ couple; hand; hold; man; woman -+ couple; gemini; hand; hold; man; twins; zodiac -+ couple; hand; hold; woman -+ emoji modifier; fitzpatrick; skin; tone -+ emoji modifier; fitzpatrick; skin; tone -+ emoji modifier; fitzpatrick; skin; tone -+ emoji modifier; fitzpatrick; skin; tone -+ emoji modifier; fitzpatrick; skin; tone -+ biceps; body; comic; flex; muscle -+ backhand; body; finger; hand; index; point -+ backhand; body; finger; hand; index; point -+ body; finger; hand; index; point; up -+ backhand; body; finger; hand; index; point; up -+ body; finger; hand -+ backhand; body; down; finger; hand; index; point -+ body; hand; v; victory -+ body; finger; hand; spock; vulcan -+ body; finger; hand; horns; rock-on -+ body; finger; hand; splayed -+ body; hand -+ body; hand; ok -+ +1; body; hand; thumb; up -+ -1; body; down; hand; thumb -+ body; clenched; fist; hand; punch -+ body; clenched; fist; hand; punch -+ body; hand; wave; waving -+ body; clap; hand -+ body; hand; open -+ body; hand; write -+ body; care; cosmetics; manicure; nail; polish -+ body -+ body -+ body; clothing; footprint; print -+ body; eye; face -+ body -+ body -+ body; lips -+ heart; kiss; lips; mark; romance -+ arrow; cupid; heart; romance -+ heart -+ beating; heart; heartbeat; pulsating -+ break; broken; heart -+ heart; love -+ excited; heart; sparkle -+ excited; growing; heart; heartpulse; nervous -+ blue; heart -+ green; heart -+ heart; yellow -+ heart; purple -+ heart; ribbon; valentine -+ heart; revolving -+ heart -+ exclamation; heart; mark; punctuation -+ heart; letter; love; mail; romance -+ comic; sleep -+ angry; comic; mad -+ comic -+ boom; comic -+ comic; splashing; sweat -+ comic; dash; running -+ comic; star -+ balloon; bubble; comic; dialog; speech -+ dialog; speech -+ angry; balloon; bubble; mad -+ balloon; bubble; comic; thought -+ hole -+ clothing; eye; eyeglasses; eyewear -+ dark; eye; eyewear; glasses -+ clothing -+ clothing; shirt; tshirt -+ clothing; pants; trousers -+ clothing -+ clothing -+ clothing; swim -+ clothing; woman -+ clothing; coin -+ bag; clothing -+ bag; clothing -+ bag; hotel; shopping -+ bag; satchel; school -+ clothing; man; shoe -+ athletic; clothing; shoe; sneaker -+ clothing; heel; shoe; woman -+ clothing; sandal; shoe; woman -+ boot; clothing; shoe; woman -+ clothing; king; queen -+ clothing; hat; woman -+ clothing; hat; top; tophat -+ cap; celebration; clothing; graduation; hat -+ beads; clothing; necklace; prayer; religion -+ cosmetics; makeup -+ diamond; romance -+ diamond; gem; jewel; romance -+ face; monkey -+ monkey -+ dog; face; pet -+ pet -+ dog -+ face; wolf -+ cat; face; pet -+ pet -+ face; leo; lion; zodiac -+ face; tiger -+ tiger -+ leopard -+ face; horse -+ racehorse; racing -+ face; unicorn -+ cow; face -+ bull; taurus; zodiac -+ buffalo; water -+ cow -+ face; pig -+ sow -+ pig -+ face; nose; pig -+ aries; sheep; zodiac -+ ewe -+ capricorn; zodiac -+ dromedary; hump -+ bactrian; camel; hump -+ elephant -+ face; mouse -+ mouse -+ rat -+ face; hamster; pet -+ bunny; face; pet; rabbit -+ bunny; pet -+ chipmunk -+ bear; face -+ bear -+ face; panda -+ feet; paw; print -+ turkey -+ chicken -+ rooster -+ baby; chick; hatching -+ baby; chick -+ baby; chick -+ bird -+ penguin -+ bird; fly; peace -+ face; frog -+ crocodile -+ turtle -+ bearer; ophiuchus; serpent; zodiac -+ dragon; face; fairy tale -+ fairy tale -+ face; spouting; whale -+ whale -+ flipper -+ pisces; zodiac -+ fish; tropical -+ fish -+ octopus -+ shell; spiral -+ cancer; zodiac -+ snail -+ insect -+ insect -+ bee; insect -+ beetle; insect; ladybird; ladybug -+ insect -+ spider; web -+ scorpio; scorpius; zodiac -+ flower; plant; romance -+ blossom; cherry; flower; plant -+ flower -+ plant -+ flower; plant -+ flower; plant -+ flower; plant; sun -+ flower; plant -+ flower; plant -+ plant; young -+ plant; tree -+ deciduous; plant; shedding; tree -+ palm; plant; tree -+ plant -+ ear; plant; rice -+ leaf; plant -+ plant -+ 4; clover; four; leaf; plant -+ falling; leaf; maple; plant -+ falling; leaf; plant -+ blow; flutter; leaf; plant; wind -+ fruit; grape; plant -+ fruit; plant -+ fruit; plant -+ fruit; orange; plant -+ citrus; fruit; plant -+ fruit; plant -+ fruit; plant -+ apple; fruit; plant; red -+ apple; fruit; green; plant -+ fruit; plant -+ fruit; plant -+ cherry; fruit; plant -+ berry; fruit; plant -+ plant; vegetable -+ aubergine; plant; vegetable -+ corn; ear; maize; maze; plant -+ hot; pepper; plant -+ plant -+ plant -+ loaf -+ cheese -+ bone; meat -+ bone; chicken; leg; poultry -+ burger -+ french; fries -+ cheese; slice -+ frankfurter; hotdog; sausage -+ mexican -+ mexican -+ popcorn -+ pot; stew -+ bento; box -+ cracker; rice -+ ball; japanese; rice -+ cooked; rice -+ curry; rice -+ bowl; noodle; ramen; steaming -+ pasta -+ potato; roasted; sweet -+ kebab; seafood; skewer; stick -+ sushi -+ fried; prawn; shrimp; tempura -+ cake; fish; pastry; swirl -+ dessert; japanese; skewer; stick; sweet -+ cream; dessert; ice; icecream; soft; sweet -+ dessert; ice; shaved; sweet -+ cream; dessert; ice; sweet -+ dessert; donut; sweet -+ dessert; sweet -+ birthday; cake; celebration; dessert; pastry; sweet -+ cake; dessert; pastry; slice; sweet -+ bar; chocolate; dessert; sweet -+ dessert; sweet -+ candy; dessert; sweet -+ dessert; pudding; sweet -+ honey; honeypot; pot; sweet -+ baby; bottle; drink; milk -+ beverage; coffee; drink; hot; steaming; tea -+ beverage; cup; drink; tea; teacup -+ bar; beverage; bottle; cup; drink -+ bar; bottle; cork; drink; popping -+ bar; beverage; drink; glass; wine -+ bar; cocktail; drink; glass -+ bar; drink; tropical -+ bar; beer; drink; mug -+ bar; beer; clink; drink; mug -+ cooking; fork; knife; plate -+ cooking; fork; knife -+ egg; frying; pan -+ aquarius; cooking; drink; jug; tool; weapon; zodiac -+ africa; earth; europe; globe; world -+ americas; earth; globe; world -+ asia; australia; earth; globe; world -+ earth; globe; meridians; world -+ map; world -+ cold; mountain; snow -+ mountain -+ eruption; mountain; weather -+ fuji; mountain -+ camping -+ beach; umbrella -+ desert -+ desert; island -+ park -+ stadium -+ building; classical -+ building; construction -+ building; house -+ building; city -+ building; derelict; house -+ building; home; house -+ building; garden; home; house -+ building; christian; cross; religion -+ islam; muslim; religion -+ islam; muslim; religion -+ jew; jewish; religion; temple -+ religion; shinto; shrine -+ building -+ building; japanese; post -+ building; european; post -+ building; doctor; medicine -+ building -+ building -+ building; hotel; love -+ building; convenience; store -+ building -+ building; department; store -+ building -+ building; castle; japanese -+ building; european -+ chapel; romance -+ tokyo; tower -+ liberty; statue -+ japan; map -+ fountain -+ camping -+ fog; weather -+ night; star; weather -+ morning; mountain; sun; sunrise; weather -+ morning; sun; weather -+ building; city; dusk; evening; landscape; sun; sunset; weather -+ building; dusk; sun; weather -+ bridge; night; weather -+ hot; hotsprings; springs; steaming -+ space; weather -+ carousel; horse -+ amusement park; ferris; wheel -+ amusement park; coaster; roller -+ barber; haircut; pole -+ circus; tent -+ art; mask; performing; theater; theatre -+ art; frame; museum; painting; picture -+ art; museum; painting; palette -+ game; slot -+ engine; railway; steam; train; vehicle -+ car; electric; railway; train; tram; trolleybus; vehicle -+ railway; shinkansen; speed; train; vehicle -+ bullet; railway; shinkansen; speed; train; vehicle -+ railway; vehicle -+ subway; vehicle -+ railway; vehicle -+ railway; train; vehicle -+ trolleybus; vehicle -+ vehicle -+ car; mountain; railway; vehicle -+ car; tram; trolleybus; vehicle -+ vehicle -+ bus; oncoming; vehicle -+ bus; tram; trolley; vehicle -+ bus; busstop; stop -+ bus; vehicle -+ vehicle -+ engine; fire; truck; vehicle -+ car; patrol; police; vehicle -+ car; oncoming; police; vehicle -+ vehicle -+ oncoming; taxi; vehicle -+ car; vehicle -+ automobile; car; oncoming; vehicle -+ recreational; rv; vehicle -+ delivery; truck; vehicle -+ lorry; semi; truck; vehicle -+ vehicle -+ bike; vehicle -+ fuel; fuelpump; gas; pump; station -+ highway; road -+ railway; train -+ beacon; car; light; police; revolving; vehicle -+ light; signal; traffic -+ light; signal; traffic -+ barrier -+ ship; tool -+ boat; resort; sea; vehicle; yacht -+ boat; vehicle -+ boat; vehicle -+ passenger; ship; vehicle -+ boat -+ boat; motorboat; vehicle -+ vehicle -+ vehicle -+ airplane; vehicle -+ airplane; check-in; departure; departures; vehicle -+ airplane; arrivals; arriving; landing; vehicle -+ chair -+ vehicle -+ railway; suspension; vehicle -+ cable; gondola; mountain; vehicle -+ aerial; cable; car; gondola; ropeway; tramway; vehicle -+ space; vehicle -+ space; vehicle -+ bell; bellhop; hotel -+ door -+ hotel; sleep -+ hotel; sleep -+ couch; hotel; lamp -+ toilet -+ water -+ bathtub; bath -+ bath -+ sand; timer -+ hourglass; sand; timer -+ clock -+ alarm; clock -+ clock -+ clock; timer -+ clock -+ 00; 12; 12:00; clock; oโ€™clock; twelve -+ 12; 12:30; 30; clock; thirty; twelve -+ 00; 1; 1:00; clock; oโ€™clock; one -+ 1; 1:30; 30; clock; one; thirty -+ 00; 2; 2:00; clock; oโ€™clock; two -+ 2; 2:30; 30; clock; thirty; two -+ 00; 3; 3:00; clock; oโ€™clock; three -+ 3; 3:30; 30; clock; thirty; three -+ 00; 4; 4:00; clock; four; oโ€™clock -+ 30; 4; 4:30; clock; four; thirty -+ 00; 5; 5:00; clock; five; oโ€™clock -+ 30; 5; 5:30; clock; five; thirty -+ 00; 6; 6:00; clock; oโ€™clock; six -+ 30; 6; 6:30; clock; six; thirty -+ 00; 7; 7:00; clock; oโ€™clock; seven -+ 30; 7; 7:30; clock; seven; thirty -+ 00; 8; 8:00; clock; eight; oโ€™clock -+ 30; 8; 8:30; clock; eight; thirty -+ 00; 9; 9:00; clock; nine; oโ€™clock -+ 30; 9; 9:30; clock; nine; thirty -+ 00; 10; 10:00; clock; oโ€™clock; ten -+ 10; 10:30; 30; clock; ten; thirty -+ 00; 11; 11:00; clock; eleven; oโ€™clock -+ 11; 11:30; 30; clock; eleven; thirty -+ dark; moon; space; weather -+ crescent; moon; space; waxing; weather -+ moon; quarter; space; weather -+ gibbous; moon; space; waxing; weather -+ full; moon; space; weather -+ gibbous; moon; space; waning; weather -+ moon; quarter; space; weather -+ crescent; moon; space; waning; weather -+ crescent; moon; space; weather -+ face; moon; space; weather -+ face; moon; quarter; space; weather -+ face; moon; quarter; space; weather -+ weather -+ bright; rays; space; sunny; weather -+ bright; face; full; moon; space; weather -+ bright; face; space; sun; weather -+ star -+ glittery; glow; shining; sparkle; star -+ falling; shooting; space; star -+ weather -+ cloud; sun; weather -+ cloud; rain; thunder; weather -+ cloud; sun; weather -+ cloud; sun; weather -+ cloud; rain; sun; weather -+ cloud; rain; weather -+ cloud; cold; snow; weather -+ cloud; lightning; weather -+ cloud; weather; whirlwind -+ cloud; weather -+ blow; cloud; face; weather; wind -+ dizzy; twister; typhoon; weather -+ rain; weather -+ clothing; rain; umbrella; weather -+ clothing; rain; weather -+ clothing; drop; rain; umbrella; weather -+ rain; sun; umbrella; weather -+ danger; electric; electricity; lightning; voltage; zap -+ cold; snow; weather -+ cold; snow; weather -+ cold; snow; snowman; weather -+ space -+ flame; tool -+ cold; comic; drop; sweat; weather -+ ocean; water; wave; weather -+ celebration; halloween; jack; lantern -+ celebration; christmas; tree -+ celebration -+ celebration; fireworks; sparkle -+ sparkle; star -+ celebration -+ celebration; party; popper; tada -+ ball; celebration; confetti -+ banner; celebration; japanese; tree -+ celebration; cross; crossed; japanese -+ bamboo; celebration; japanese; pine; plant -+ celebration; doll; festival; japanese -+ carp; celebration; streamer -+ bell; celebration; chime; wind -+ celebration; ceremony; moon -+ celebration -+ box; celebration; gift; present; wrapped -+ celebration; medal; military -+ celebration; reminder; ribbon -+ cinema; film; frames; movie -+ admission; ticket -+ admission -+ label -+ ball; soccer -+ ball -+ ball; hoop -+ american; ball; football -+ ball; football; rugby -+ ball; racquet -+ 8; 8 ball; ball; billiard; eight; game -+ ball; game -+ golf; hole -+ ball; golf -+ ice; skate -+ fish; pole -+ running; sash; shirt -+ ski; snow -+ ski; snow -+ ski; snow; snowboard -+ surfing -+ horse; jockey; racehorse; racing -+ swim -+ ball -+ lifter; weight -+ bicycle; bike; cyclist -+ bicycle; bicyclist; bike; cyclist; mountain -+ car; racing -+ racing -+ medal -+ prize -+ ball; bat; game -+ ball; game -+ ball; field; game; hockey; stick -+ game; hockey; ice; puck; stick -+ ball; bat; game; paddle; table tennis -+ birdie; game; racquet; shuttlecock -+ bull; bullseye; dart; eye; game; hit; target -+ controller; game -+ game; video game -+ dice; die; game -+ card; game; spade; suit -+ card; game; heart; hearts; suit -+ card; diamond; diamonds; game; suit -+ card; club; clubs; game; suit -+ card; game; playing -+ game; mahjong; red -+ card; flower; game; japanese; playing -+ mute; quiet; silent; speaker; volume -+ volume -+ low; speaker; volume; wave -+ 3; high; loud; speaker; three; volume -+ loud; public address -+ cheering -+ horn; post; postal -+ bell -+ bell; forbidden; mute; no; not; prohibited; quiet; silent -+ music; score -+ music; note -+ music; note; notes -+ mic; microphone; music; studio -+ level; music; slider -+ control; knobs; music -+ karaoke; mic -+ earbud -+ instrument; music; sax -+ instrument; music -+ instrument; keyboard; music; piano -+ instrument; music -+ instrument; music -+ video -+ cell; mobile; phone; telephone -+ arrow; call; cell; mobile; phone; receive; telephone -+ phone -+ phone; receiver; telephone -+ pager -+ fax -+ battery -+ electric; electricity; plug -+ computer; pc; personal -+ computer; desktop -+ computer -+ computer -+ 3; button; computer; mouse; three -+ computer -+ computer; disk; minidisk; optical -+ computer; disk; floppy -+ dvd; blu-ray; cd; computer; disk; optical -+ blu-ray; cd; computer; disk; optical -+ camera; cinema; movie -+ clapper; movie -+ cinema; film; movie; projector; video -+ tv; video -+ video -+ camera; flash; video -+ camera; video -+ tape; vhs; video -+ glass; magnifying; search; tool -+ glass; magnifying; search; tool -+ tool -+ tool -+ antenna; dish; satellite -+ light -+ bulb; comic; electric; idea; light -+ electric; light; tool; torch -+ bar; japanese; lantern; light; red -+ book; cover; decorated; notebook -+ book; closed -+ book; open -+ book; green -+ blue; book -+ book; orange -+ book -+ notebook -+ notebook -+ curl; document; page -+ paper -+ document; page -+ news; paper -+ news; newspaper; paper; rolled -+ bookmark; mark; marker; tabs -+ mark -+ bag; dollar; money; moneybag -+ bank; banknote; bill; currency; money; note; yen -+ bank; banknote; bill; currency; dollar; money; note -+ bank; banknote; bill; currency; euro; money; note -+ bank; banknote; bill; currency; money; note; pound -+ bank; banknote; bill; dollar; fly; money; note; wings -+ bank; card; credit; money -+ bank; chart; currency; graph; growth; market; money; rise; trend; upward; yen -+ e-mail; email -+ email; letter; mail -+ e-mail; email; envelope; incoming; letter; mail; receive -+ arrow; down; e-mail; email; envelope; letter; mail; outgoing; sent -+ box; letter; mail; outbox; sent; tray -+ box; inbox; letter; mail; receive; tray -+ box; parcel -+ closed; mail; mailbox; postbox -+ closed; lowered; mail; mailbox; postbox -+ mail; mailbox; open; postbox -+ lowered; mail; mailbox; open; postbox -+ mail; mailbox -+ ballot; box -+ pencil -+ nib; pen -+ fountain; pen -+ ballpoint -+ painting -+ crayon -+ pencil -+ briefcase -+ file; folder -+ file; folder; open -+ card; dividers; index -+ date -+ calendar -+ note; pad; spiral -+ calendar; pad; spiral -+ card; index; rolodex -+ chart; graph; growth; trend; upward -+ chart; down; graph; trend -+ bar; chart; graph -+ clipboard -+ pin -+ pin; pushpin -+ paperclip -+ link; paperclip -+ ruler; straight edge -+ ruler; set; triangle -+ tool -+ box; card; file -+ cabinet; file -+ wastebasket -+ closed -+ lock; open; unlock -+ ink; lock; nib; pen; privacy -+ closed; key; lock; secure -+ lock; password -+ clue; key; lock; old -+ tool -+ mining; tool -+ hammer; pick; tool -+ hammer; tool; wrench -+ tool -+ bolt; nut; tool -+ tool -+ tool; vice -+ chemistry; tool -+ balance; justice; libra; scales; tool; weight; zodiac -+ link -+ chain -+ doctor; medicine; needle; shot; sick; tool -+ doctor; medicine; sick -+ knife; weapon -+ cooking; hocho; knife; tool; weapon -+ crossed; swords; weapon -+ gun; handgun; revolver; tool; weapon -+ weapon -+ archer; arrow; bow; sagittarius; tool; weapon; zodiac -+ checkered; chequered; racing -+ waving -+ waving -+ post -+ smoking -+ death -+ death; funeral; urn -+ face; moyai; statue -+ drum; oil -+ ball; crystal; fairy tale; fantasy; fortune; tool -+ atm; automated; bank; teller -+ litter; litterbox -+ drink; potable; water -+ access -+ lavatory; man; restroom; wc -+ lavatory; restroom; wc; woman -+ lavatory; wc -+ baby; changing -+ closet; lavatory; restroom; water; wc -+ control; passport -+ customs -+ baggage; claim -+ baggage; locker; luggage -+ warning -+ child; crossing; pedestrian; traffic -+ entry; forbidden; no; not; prohibited; traffic -+ entry; forbidden; no; not -+ bicycle; bike; forbidden; no; not; prohibited; vehicle -+ forbidden; no; not; prohibited; smoking -+ forbidden; litter; no; not; prohibited -+ drink; forbidden; no; not; potable; prohibited; water -+ forbidden; no; not; pedestrian; prohibited -+ radioactive -+ biohazard -+ arrow; cardinal; direction; north -+ arrow; direction; intercardinal; northeast -+ arrow; cardinal; direction; east -+ arrow; direction; intercardinal; southeast -+ arrow; cardinal; direction; down; south -+ arrow; direction; intercardinal; southwest -+ arrow; cardinal; direction; west -+ arrow; direction; intercardinal; northwest -+ arrow -+ arrow -+ arrow -+ arrow -+ arrow -+ arrow; down -+ arrow; clockwise; reload -+ anticlockwise; arrow; counterclockwise; withershins -+ arrow; back -+ arrow; end -+ arrow; mark; on -+ arrow; soon -+ arrow; top; up -+ religion; worship -+ atheist; atom -+ hindu; religion -+ david; jew; jewish; religion; star -+ buddhist; dharma; religion; wheel -+ religion; tao; taoist; yang; yin -+ christian; cross; religion -+ christian; cross; religion -+ islam; muslim; religion -+ peace -+ candelabrum; candlestick; religion -+ fortune; star -+ recycle -+ badge; name -+ fleur-de-lis -+ beginner; chevron; green; japanese; leaf; tool; yellow -+ anchor; emblem; ship; tool; trident -+ circle; o -+ check; mark -+ ballot; box; check -+ check; mark -+ cancel; multiplication; multiply; x -+ cancel; mark; multiplication; multiply; x -+ mark; square -+ math; plus -+ math; minus -+ division; math -+ curl; loop -+ curl; double; loop -+ mark; part -+ asterisk -+ star -+ sparkle -+ bank; currency; exchange; money -+ currency; dollar; money -+ bangbang; exclamation; mark; punctuation -+ exclamation; interrobang; mark; punctuation; question -+ mark; punctuation; question -+ mark; outlined; punctuation; question -+ exclamation; mark; outlined; punctuation -+ exclamation; mark; punctuation -+ dash; punctuation; wavy -+ copyright -+ registered -+ mark; tm; trademark -+ ram; zodiac -+ bull; ox; zodiac -+ twins; zodiac -+ crab; zodiac -+ lion; zodiac -+ maiden; virgin; zodiac -+ balance; justice; scales; zodiac -+ scorpio; scorpion; zodiac -+ archer; zodiac -+ goat; zodiac -+ bearer; water; zodiac -+ fish; zodiac -+ bearer; serpent; snake; zodiac -+ arrow; crossed -+ arrow; clockwise; repeat -+ arrow; clockwise; once -+ arrow; play; right; triangle -+ arrow; double; fast; forward -+ arrow; next scene; next track; triangle -+ arrow; pause; play; right; triangle -+ arrow; left; reverse; triangle -+ arrow; double; rewind -+ arrow; previous scene; previous track; triangle -+ arrow; button; red -+ arrow; double -+ arrow; button; down; red -+ arrow; double; down -+ bar; double; pause; vertical -+ square; stop -+ circle; record -+ eject -+ camera; film; movie -+ brightness; dim; low -+ bright; brightness -+ antenna; bar; cell; mobile; phone; signal; telephone -+ cell; forbidden; mobile; no; not; phone; prohibited; telephone -+ cell; mobile; mode; phone; telephone; vibration -+ cell; mobile; off; phone; telephone -+ hash; keycap; pound -+ asterisk; keycap; star -+ 0; keycap; zero -+ 1; keycap; one -+ 2; keycap; two -+ 3; keycap; three -+ 4; four; keycap -+ 5; five; keycap -+ 6; keycap; six -+ 7; keycap; seven -+ 8; eight; keycap -+ 9; keycap; nine -+ 10; keycap; ten -+ 100; full; hundred; score -+ 18; age restriction; eighteen; forbidden; no; not; prohibited; underage -+ input; latin; letters; uppercase -+ abcd; input; latin; letters; lowercase -+ 1234; input; numbers -+ input -+ abc; alphabet; input; latin; letters -+ a; blood -+ ab; blood -+ b; blood -+ cl -+ cool -+ free -+ i; information -+ id; identity -+ circle; m -+ new -+ ng -+ blood; o -+ ok -+ parking -+ help; sos -+ mark; up -+ versus; vs -+ japanese -+ japanese -+ japanese -+ japanese -+ japanese -+ japanese -+ japanese -+ japanese -+ japanese -+ chinese -+ chinese -+ chinese -+ chinese -+ chinese; congratulation; congratulations; ideograph -+ chinese; ideograph; secret -+ chinese -+ chinese -+ geometric; square -+ geometric; square -+ geometric; square -+ geometric; square -+ geometric; square -+ geometric; square -+ geometric; square -+ geometric; square -+ diamond; geometric; orange -+ blue; diamond; geometric -+ diamond; geometric; orange -+ blue; diamond; geometric -+ geometric; red -+ down; geometric; red -+ comic; diamond; geometric; inside -+ button; geometric; radio -+ button; geometric; square -+ button; geometric; outlined; square -+ circle; geometric -+ circle; geometric -+ circle; geometric; red -+ blue; circle; geometric -+ -+ -\ No newline at end of file -diff --git a/ibus.spec.in b/ibus.spec.in -index 7fdaccb..40aead1 100644 ---- a/ibus.spec.in -+++ b/ibus.spec.in -@@ -5,6 +5,7 @@ - - # Build flags - %define build_python_library 0 -+%define build_emoji_dictionary 1 - - %define glib_ver %([ -a %{_libdir}/pkgconfig/glib-2.0.pc ] && pkg-config --modversion glib-2.0 | cut -d. -f 1,2 || echo -n "999") - %define gconf2_version 2.12.0 -@@ -40,6 +41,10 @@ BuildRequires: dconf-devel - BuildRequires: pygobject2-devel - BuildRequires: intltool - BuildRequires: iso-codes-devel -+%if %build_emoji_dictionary -+BuildRequires: nodejs-emojione -+BuildRequires: json-glib -+%endif - - Requires: %{name}-libs = %{version}-%{release} - Requires: %{name}-gtk2 = %{version}-%{release} -@@ -151,6 +156,12 @@ OPTIONS="$OPTIONS --enable-python-library" - %else - OPTIONS="$OPTIONS --disable-python-library" - %endif -+%if %build_emoji_dictionary -+OPTIONS="$OPTIONS --enable-emoji-dict" -+%else -+OPTIONS="$OPTIONS --disable-emoji-dict" -+%endif -+ - - %configure $OPTIONS - -@@ -258,6 +269,9 @@ dconf update &> /dev/null || : - %{_bindir}/ibus-setup - %{_datadir}/ibus/component/gtkpanel.xml - %{_datadir}/ibus/component/simple.xml -+%if %build_emoji_dictionary -+%{_datadir}/ibus/dicts -+%endif - %{_datadir}/ibus/keymaps/* - %{_datadir}/ibus/setup/* - -diff --git a/src/Makefile.am b/src/Makefile.am -index 22e031f..b58ab95 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -29,15 +29,6 @@ endif - - SUBDIRS = . $(TESTS_DIR) - --IBUS_V_wget = $(ibus__v_wget_@AM_V@) --ibus__v_wget_ = $(ibus__v_wget_@AM_DEFAULT_V@) --ibus__v_wget_0 = -nv --ibus__v_wget_1 = --IBUS_V_diff = $(ibus__v_diff_@AM_V@) --ibus__v_diff_ = $(ibus__v_diff_@AM_DEFAULT_V@) --ibus__v_diff_0 = -q --ibus__v_diff_1 = -- - # libibus = libibus-@IBUS_API_VERSION@.la - libibus = libibus-1.0.la - -@@ -248,37 +239,25 @@ dict_DATA = emoji.dict - - noinst_PROGRAMS = emoji-parser - --emoji-list.html: -- $(AM_V_at)wget $(IBUS_V_wget) \ -- http://ibus.github.io/files/ibus/emoji-list.html -- $(AM_V_at)wget $(IBUS_V_wget) \ -- http://unicode.org/emoji/charts/emoji-list.html \ -- -O latest-emoji-list.html -- $(AM_V_at)diff $(IBUS_V_diff) emoji-list.html latest-emoji-list.html; \ -- if test $$? -ne 0; then \ -- echo "#### WARNING: emoji-list.html is old." >&2; \ -- fi; \ -- rm latest-emoji-list.html; -- --emoji.dict: emoji-parser emoji-list.html -- $(builddir)/emoji-parser emoji-list.html $@ -+emoji.dict: emoji-parser -+ $(builddir)/emoji-parser --xml $(srcdir)/../data/annotations/en.xml \ -+ --json $(EMOJI_JSON_FILE) --out $@ - - emoji_parser_SOURCES = \ - emoji-parser.c \ - $(NULL) - emoji_parser_CFLAGS = \ - $(GLIB2_CFLAGS) \ -- $(LIBXML2_CFLAGS) \ -+ $(JSON_GLIB1_CFLAGS) \ - $(NULL) - emoji_parser_LDADD = \ - $(GLIB2_LIBS) \ -- $(LIBXML2_LIBS) \ -+ $(JSON_GLIB1_LIBS) \ - $(libibus) \ - $(NULL) - - CLEANFILES += \ - $(dict_DATA) \ -- emoji-list.html \ - $(NULL) - endif - -diff --git a/src/emoji-parser.c b/src/emoji-parser.c -index cf92fee..e97f266 100644 ---- a/src/emoji-parser.c -+++ b/src/emoji-parser.c -@@ -20,47 +20,59 @@ - * USA - */ - --/* Convert http://www.unicode.org/emoji/charts/emoji-list.html -+/* Convert ../data/annotations/en.xml and -+ * /usr/lib/node_modules/emojione/emoji.json - * to the dictionary file which look up the Emoji from the annotation. -+ * Get emoji.json with 'npm install -g emojione'. -+ * en.xml is used for the Unicode annotations and emoji.json is used -+ * for the aliases_ascii, e.g. ":)", and category, e.g. "people". - */ - - #include --#include --#include -+#include -+ -+#include - - #include "ibusutil.h" - - typedef struct _EmojiData EmojiData; - struct _EmojiData { -- gchar *class; - gchar *emoji; -- GSList *annotates; -- GSList *prev_annotates; -+ GSList *annotations; -+ gboolean is_annotation; - GHashTable *dict; - }; - --const gchar *progname; -- --static gboolean parse_node (xmlNode *node, -- gboolean is_child, -- const gchar *prop_name, -- EmojiData *data); -- - static void --usage (void) -+reset_emoji_element (EmojiData *data) - { -- g_print ("%s emoji-list.html emoji.dict\n", progname); -+ g_assert (data != NULL); -+ -+ g_clear_pointer (&data->emoji, g_free); -+ g_slist_free_full (data->annotations, g_free); -+ data->annotations = NULL; - } - - static void --reset_emoji_element (EmojiData *data) -+update_emoji_dict (EmojiData *data) - { -- g_clear_pointer (&data->class, g_free); -- g_clear_pointer (&data->emoji, g_free); -- if (data->annotates) { -- g_slist_free_full (data->prev_annotates, g_free); -- data->prev_annotates = data->annotates; -- data->annotates = NULL; -+ GSList *annotations = data->annotations; -+ while (annotations) { -+ const gchar *annotation = (const gchar *) annotations->data; -+ GSList *emojis = g_hash_table_lookup (data->dict, annotation); -+ if (emojis) { -+ GSList *duplicated = g_slist_find_custom (emojis, -+ data->emoji, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated != NULL) -+ continue; -+ emojis = g_slist_copy_deep (emojis, (GCopyFunc) g_strdup, NULL); -+ } -+ emojis = g_slist_append (emojis, g_strdup (data->emoji)); -+ g_hash_table_replace (data->dict, -+ g_strdup (annotation), -+ emojis); -+ annotations = annotations->next; - } - } - -@@ -70,147 +82,486 @@ free_dict_words (gpointer list) - g_slist_free_full (list, g_free); - } - --static gboolean --parse_attr (xmlAttr *attr, -- EmojiData *data) --{ -- if (g_strcmp0 ((const gchar *) attr->name, "class") == 0 && attr->children) -- parse_node (attr->children, TRUE, (const gchar *) attr->name, data); -- if (g_strcmp0 ((const gchar *) attr->name, "target") == 0 && attr->children) -- parse_node (attr->children, TRUE, (const gchar *) attr->name, data); -- if (attr->next) -- parse_attr (attr->next, data); -- return TRUE; --} -+static void -+unicode_annotations_start_element_cb (GMarkupParseContext *context, -+ const gchar *element_name, -+ const gchar **attribute_names, -+ const gchar **attribute_values, -+ gpointer user_data, -+ GError **error) -+{ -+ EmojiData *data = (EmojiData *) user_data; -+ int i; -+ const gchar *attribute; -+ const gchar *value; - --static gboolean --parse_node (xmlNode *node, -- gboolean is_child, -- const gchar *prop_name, -- EmojiData *data) --{ -- if (g_strcmp0 ((const gchar *) node->name, "tr") == 0) { -- GSList *annotates = data->annotates; -- while (annotates) { -- GSList *emojis = g_hash_table_lookup (data->dict, annotates->data); -- if (emojis) { -- emojis = g_slist_copy_deep (emojis, (GCopyFunc) g_strdup, NULL); -+ g_assert (data != NULL); -+ -+ if (g_strcmp0 (element_name, "annotation") != 0) -+ return; -+ -+ reset_emoji_element (data); -+ -+ for (i = 0; (attribute = attribute_names[i]) != NULL; i++) { -+ value = attribute_values[i]; -+ -+ if (g_strcmp0 (attribute, "cp") == 0) { -+ if (value == NULL || *value == '\0') { -+ g_warning ("cp='' in unicode.org annotations file"); -+ return; -+ } else if (value[0] != '[' || value[strlen(value) - 1] != ']') { -+ g_warning ("cp!='[emoji]' in unicode.org annotations file"); -+ return; - } -- emojis = g_slist_append (emojis, g_strdup (data->emoji)); -- g_hash_table_replace (data->dict, -- g_strdup (annotates->data), -- emojis); -- annotates = annotates->next; -+ data->emoji = g_strndup (value + 1, strlen(value) - 2); - } -- reset_emoji_element (data); -- } -- /* if node->name is "text" and is_child is FALSE, -- * it's '\n' or Space between and . -- */ -- if (g_strcmp0 ((const gchar *) node->name, "text") == 0 && is_child) { -- /* Get "chars" in */ -- if (g_strcmp0 (prop_name, "class") == 0) { -- if (g_strcmp0 (data->class, (const gchar *) node->content) != 0) { -- g_clear_pointer (&data->class, g_free); -- data->class = g_strdup ((const gchar *) node->content); -+ else if (g_strcmp0 (attribute, "tts") == 0) { -+ GSList *duplicated = g_slist_find_custom (data->annotations, -+ value, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated == NULL) { -+ data->annotations = g_slist_prepend (data->annotations, -+ g_strdup (value)); - } - } -- /* Get "annotate" in */ -- if (g_strcmp0 (prop_name, "target") == 0 && -- g_strcmp0 (data->class, "name") == 0) { -- g_clear_pointer (&data->class, g_free); -- data->class = g_strdup ((const gchar *) node->content); -- } -- /* Get "emoji" in emoji */ -- if (g_strcmp0 (prop_name, "td") == 0 && -- g_strcmp0 (data->class, "chars") == 0) { -- data->emoji = g_strdup ((const gchar *) node->content); -- } -- /* We ignore "NAME" for NAME but -- * takes "ANNOTATE" for -- * ANNOTATE -- */ -- if (g_strcmp0 (prop_name, "td") == 0 && -- g_strcmp0 (data->class, "name") == 0) { -- g_slist_free_full (data->annotates, g_free); -- data->annotates = NULL; -+ } -+ -+ data->is_annotation = TRUE; -+} -+ -+static void -+unicode_annotations_end_element_cb (GMarkupParseContext *context, -+ const gchar *element_name, -+ gpointer user_data, -+ GError **error) -+{ -+ EmojiData *data = (EmojiData *) user_data; -+ -+ g_assert (data != NULL); -+ if (!data->is_annotation) -+ return; -+ -+ update_emoji_dict (data); -+ data->is_annotation = FALSE; -+} -+ -+void -+unicode_annotations_text_cb (GMarkupParseContext *context, -+ const gchar *text, -+ gsize text_len, -+ gpointer user_data, -+ GError **error) -+{ -+ EmojiData *data = (EmojiData *) user_data; -+ gchar **annotations = NULL; -+ const gchar *annotation; -+ int i; -+ -+ g_assert (data != NULL); -+ if (!data->is_annotation) -+ return; -+ annotations = g_strsplit (text, "; ", -1); -+ for (i = 0; (annotation = annotations[i]) != NULL; i++) { -+ GSList *duplicated = g_slist_find_custom (data->annotations, -+ annotation, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated == NULL) { -+ data->annotations = g_slist_prepend (data->annotations, -+ g_strdup (annotation)); - } -- /* Get "ANNOTATE" in -- * ANNOTATE -- */ -- if (g_strcmp0 (prop_name, "a") == 0 && -- g_strcmp0 (data->class, "annotate") == 0) { -- data->annotates = -- g_slist_append (data->annotates, -- g_strdup ((const gchar *) node->content)); -+ } -+ g_strfreev (annotations); -+} -+ -+static gboolean -+unicode_annotations_parse_xml_file (const gchar *filename, -+ GHashTable *dict) -+{ -+ gchar *content = NULL; -+ gsize length = 0; -+ GError *error = NULL; -+ const static GMarkupParser parser = { -+ unicode_annotations_start_element_cb, -+ unicode_annotations_end_element_cb, -+ unicode_annotations_text_cb, -+ NULL, -+ NULL -+ }; -+ GMarkupParseContext *context = NULL; -+ EmojiData data = { 0, }; -+ -+ g_return_val_if_fail (filename != NULL, FALSE); -+ g_return_val_if_fail (dict != NULL, FALSE); -+ -+ if (!g_file_get_contents (filename, &content, &length, &error)) { -+ g_warning ("Failed to load %s: %s", filename, error->message); -+ goto failed_to_parse_unicode_annotations; -+ } -+ -+ data.dict = dict; -+ -+ context = g_markup_parse_context_new (&parser, 0, &data, NULL); -+ if (!g_markup_parse_context_parse (context, content, length, &error)) { -+ g_warning ("Failed to parse %s: %s", filename, error->message); -+ goto failed_to_parse_unicode_annotations; -+ } -+ -+ reset_emoji_element (&data); -+ g_markup_parse_context_free (context); -+ g_free (content); -+ return TRUE; -+ -+failed_to_parse_unicode_annotations: -+ if (error) -+ g_error_free (error); -+ if (data.dict) -+ g_hash_table_destroy (data.dict); -+ if (context) -+ g_markup_parse_context_free (context); -+ g_free (content); -+ return FALSE; -+} -+ -+static gboolean -+parse_emojione_unicode (JsonNode *node, -+ EmojiData *data) -+{ -+ const gchar *str, *unicode; -+ gchar *endptr = NULL; -+ guint32 uch; -+ static gchar outbuf[8] = { 0, }; -+ GString *emoji; -+ -+ if (json_node_get_node_type (node) != JSON_NODE_VALUE) { -+ g_warning ("'unicode' element is not string"); -+ return FALSE; -+ } -+ -+ emoji = g_string_new (NULL); -+ str = unicode = json_node_get_string (node); -+ while (str && *str) { -+ uch = g_ascii_strtoull (str, &endptr, 16); -+ outbuf[g_unichar_to_utf8 (uch, outbuf)] = '\0'; -+ g_string_append (emoji, outbuf); -+ if (*endptr == '\0') { -+ break; -+ } else { -+ switch (*endptr) { -+ case '-': -+ endptr++; -+ break; -+ default: -+ g_warning ("Failed to parse unicode %s", unicode); -+ } - } -+ str = endptr; -+ endptr = NULL; -+ } -+ -+ data->emoji = g_string_free (emoji, FALSE); -+ -+ return TRUE; -+} -+ -+static gboolean -+parse_emojione_shortname (JsonNode *node, -+ EmojiData *data) -+{ -+#if 0 -+ const gchar *shortname; -+ gchar *head, *s; -+ int length; -+ GSList *duplicated; -+ -+ if (json_node_get_node_type (node) != JSON_NODE_VALUE) { -+ g_warning ("'shortname' element is not string"); -+ return FALSE; - } -- /* Get "foo" in */ -- if (g_strcmp0 ((const gchar *) node->name, "td") == 0 && -- node->properties != NULL) { -- parse_attr (node->properties, data); -+ -+ /* The format is ':short_name:' */ -+ shortname = json_node_get_string (node); -+ if (shortname == 0 || *shortname == '\0') -+ return TRUE; -+ if (*shortname != ':') { -+ g_warning ("'shortname' format is different: %s", shortname); -+ return FALSE; - } -- /* Get "foo" in */ -- if (g_strcmp0 ((const gchar *) node->name, "a") == 0 && -- node->properties != NULL) { -- parse_attr (node->properties, data); -+ -+ length = strlen (shortname); -+ head = g_new0 (gchar, length); -+ strcpy (head, shortname + 1); -+ for (s = head; *s; s++) { -+ if (*s == ':') { -+ *s = '\0'; -+ break; -+ } else if (*s == '_') { -+ *s = ' '; -+ } - } -- if (node->children) { -- parse_node (node->children, TRUE, (const gchar *) node->name, data); -+ -+ if (head == NULL || *head == '\0') { -+ g_warning ("'shortname' format is different: %s", shortname); -+ g_free (head); -+ return FALSE; -+ } -+ -+ duplicated = g_slist_find_custom (data->annotations, -+ head, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated == NULL) { -+ data->annotations = g_slist_prepend (data->annotations, -+ head); - } else { -- /* If annotate is NULL likes , -- * the previous emoji cell has the same annotate. -- */ -- if (g_strcmp0 ((const gchar *) node->name, "td") == 0 && -- g_strcmp0 (data->class, "name") == 0) { -- data->annotates = g_slist_copy_deep (data->prev_annotates, -- (GCopyFunc) g_strdup, -- NULL); -+ g_free (head); -+ } -+ -+#endif -+ return TRUE; -+} -+ -+static gboolean -+parse_emojione_category (JsonNode *node, -+ EmojiData *data) -+{ -+ const gchar *category; -+ GSList *duplicated; -+ -+ if (json_node_get_node_type (node) != JSON_NODE_VALUE) { -+ g_warning ("'category' element is not string"); -+ return FALSE; -+ } -+ -+ category = json_node_get_string (node); -+ -+ if (category == NULL || *category == '\0') -+ return TRUE; -+ -+ duplicated = g_slist_find_custom (data->annotations, -+ category, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated == NULL) { -+ data->annotations = g_slist_prepend (data->annotations, -+ g_strdup (category)); -+ } -+ -+ return TRUE; -+} -+ -+static gboolean -+parse_emojione_aliases_ascii (JsonNode *node, -+ EmojiData *data) -+{ -+ JsonArray *aliases_ascii; -+ guint i, length; -+ -+ if (json_node_get_node_type (node) != JSON_NODE_ARRAY) { -+ g_warning ("'aliases_ascii' element is not array"); -+ return FALSE; -+ } -+ -+ aliases_ascii = json_node_get_array (node); -+ length = json_array_get_length (aliases_ascii); -+ for (i = 0; i < length; i++) { -+ const gchar *alias = json_array_get_string_element (aliases_ascii, i); -+ GSList *duplicated = g_slist_find_custom (data->annotations, -+ alias, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated == NULL) { -+ data->annotations = g_slist_prepend (data->annotations, -+ g_strdup (alias)); - } - } -- if (node->next) -- parse_node (node->next, FALSE, (const gchar *) node->name, data); - - return TRUE; - } - --static GHashTable * --parse_html (const gchar *filename) -+static gboolean -+parse_emojione_keywords (JsonNode *node, -+ EmojiData *data) - { -- xmlDoc *doc = htmlParseFile (filename, "utf-8"); -- EmojiData data = { 0, }; -+#if 0 -+ JsonArray *keywords; -+ guint i, length; - -- if (doc == NULL || doc->children == NULL) { -- g_warning ("Parse Error in document type: %x", -- doc ? doc->type : 0); -+ if (json_node_get_node_type (node) != JSON_NODE_ARRAY) { -+ g_warning ("'keywords' element is not array"); - return FALSE; - } - -- data.dict = g_hash_table_new_full (g_str_hash, -- g_str_equal, -- g_free, -- free_dict_words); -- parse_node (doc->children, TRUE, (const gchar *) doc->name, &data); -+ keywords = json_node_get_array (node); -+ length = json_array_get_length (keywords); -+ for (i = 0; i < length; i++) { -+ const gchar *keyword = json_array_get_string_element (keywords, i); -+ GSList *duplicated = g_slist_find_custom (data->annotations, -+ keyword, -+ (GCompareFunc) g_strcmp0); -+ if (duplicated == NULL) { -+ data->annotations = g_slist_prepend (data->annotations, -+ g_strdup (keyword)); -+ } -+ } - -+#endif -+ return TRUE; -+} -+ -+static gboolean -+parse_emojione_emoji_data (JsonNode *node, -+ const gchar *member, -+ EmojiData *data) -+{ -+ if (g_strcmp0 (member, "unicode") == 0) -+ return parse_emojione_unicode (node, data); -+ else if (g_strcmp0 (member, "shortname") == 0) -+ return parse_emojione_shortname (node, data); -+ else if (g_strcmp0 (member, "category") == 0) -+ return parse_emojione_category (node, data); -+ else if (g_strcmp0 (member, "aliases_ascii") == 0) -+ return parse_emojione_aliases_ascii (node, data); -+ else if (g_strcmp0 (member, "keywords") == 0) -+ return parse_emojione_keywords (node, data); -+ return TRUE; -+} -+ -+static gboolean -+parse_emojione_element (JsonNode *node, -+ EmojiData *data) -+{ -+ JsonObject *object; -+ GList *members, *m; -+ -+ if (json_node_get_node_type (node) != JSON_NODE_OBJECT) { -+ return FALSE; -+ } -+ -+ reset_emoji_element (data); -+ -+ object = json_node_get_object (node); -+ m = members = json_object_get_members (object); -+ while (m) { -+ const gchar *member = (const gchar *) m->data; -+ if (!parse_emojione_emoji_data (json_object_get_member (object, member), -+ member, -+ data)) { -+ g_list_free (members); -+ return FALSE; -+ } -+ m = m->next; -+ } -+ g_list_free (members); -+ -+ update_emoji_dict (data); -+ -+ return TRUE; -+} -+ -+static gboolean -+emojione_parse_json_file (const gchar *filename, -+ GHashTable *dict) -+{ -+ JsonParser *parser = json_parser_new (); -+ JsonNode *node; -+ JsonObject *object; -+ GList *members, *m; -+ GError *error = NULL; -+ EmojiData data = { 0, }; -+ -+ g_return_val_if_fail (filename != NULL, FALSE); -+ g_return_val_if_fail (dict != NULL, FALSE); -+ -+ if (!json_parser_load_from_file (parser, filename, &error)) { -+ g_error ("%s", error->message); -+ g_error_free (error); -+ goto fail_to_json_file; -+ } -+ -+ node = json_parser_get_root (parser); -+ if (json_node_get_node_type (node) != JSON_NODE_OBJECT) { -+ g_warning ("Json file does not have Json object %s", filename); -+ goto fail_to_json_file; -+ } -+ -+ object = json_node_get_object (node); -+ members = json_object_get_members (object); -+ data.dict = dict; -+ -+ m = members; -+ while (m) { -+ const gchar *member = (const gchar *) m->data; -+ if (!parse_emojione_element (json_object_get_member (object, member), -+ &data)) { -+ g_warning ("Failed to parse member '%s' in %s", member, filename); -+ } -+ m = m->next; -+ } -+ -+ g_list_free (members); - reset_emoji_element (&data); -- g_slist_free_full (data.prev_annotates, g_free); -+ g_object_unref (parser); -+ -+ return TRUE; - -- return data.dict; -+fail_to_json_file: -+ g_object_unref (parser); -+ return FALSE; - } - - int - main (int argc, char *argv[]) - { -+ gchar *prgname; -+ gchar *json_file = NULL; -+ gchar *xml_file = NULL; -+ gchar *output = NULL; -+ GOptionEntry entries[] = { -+ { "json", 'j', 0, G_OPTION_ARG_STRING, &json_file, -+ "Parse Emoji One JSON file", -+ "JSON" -+ }, -+ { "out", 'o', 0, G_OPTION_ARG_STRING, &output, -+ "Save the emoji dictionary as FILE", -+ "FILE" -+ }, -+ { "xml", 'x', 0, G_OPTION_ARG_STRING, &xml_file, -+ "Parse Unocode.org ANNOTATIONS file", -+ "ANNOTATIONS" -+ }, -+ { NULL } -+ }; -+ GOptionContext *context; -+ GError *error = NULL; - GHashTable *dict; -- progname = basename (argv[0]); -+ -+ prgname = g_path_get_basename (argv[0]); -+ g_set_prgname (prgname); -+ g_free (prgname); -+ -+ context = g_option_context_new (NULL); -+ g_option_context_add_main_entries (context, entries, NULL); - - if (argc < 3) { -- usage (); -+ g_print ("%s", g_option_context_get_help (context, TRUE, NULL)); -+ g_option_context_free (context); -+ return -1; -+ } -+ -+ if (!g_option_context_parse (context, &argc, &argv, &error)) { -+ g_warning ("Failed options: %s", error->message); -+ g_error_free (error); - return -1; - } -+ g_option_context_free (context); - -- dict = parse_html (argv[1]); -- ibus_emoji_dict_save (argv[2], dict); -+ dict = g_hash_table_new_full (g_str_hash, -+ g_str_equal, -+ g_free, -+ free_dict_words); -+ if (xml_file) -+ unicode_annotations_parse_xml_file (xml_file, dict); -+ if (json_file) -+ emojione_parse_json_file (json_file, dict); -+ if (g_hash_table_size (dict) > 0 && output) -+ ibus_emoji_dict_save (output, dict); - g_hash_table_destroy (dict); - - return 0; --- -2.7.4 - -From f88c48750538eaaf7c7b182ba3763b45c2745074 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 20 Jul 2016 11:43:49 +0900 -Subject: [PATCH 4/4] Fix typo in configure.ac - -R=shawn.p.huang@gmail.com - -Review URL: https://codereview.appspot.com/303110043 ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index f789819..76897f0 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -647,7 +647,7 @@ engine/Makefile - util/Makefile - util/IMdkit/Makefile - data/Makefile --data/annotations/Makefile.am -+data/annotations/Makefile - data/icons/Makefile - data/keymaps/Makefile - data/dconf/Makefile --- -2.7.4 -