From bfe57d20e9d39d52428e95e493d9af0bd034a82f Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 15 Jan 2018 14:44:07 +0900 Subject: [PATCH] Added DBus filtering against malware The proposal prevents non-ower of the GDBusConnection from accessing DBus methods against malicious usages. BUG=https://github.com/ibus/ibus/issues/1955 Review URL: https://codereview.appspot.com/335380043 --- bus/inputcontext.c | 24 +++++++++++++++++++++++- src/ibusengine.c | 18 +++++++++++++++++- src/ibuspanelservice.c | 14 +++++++++++++- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/bus/inputcontext.c b/bus/inputcontext.c index d8be9e3f..4f2ecafc 100644 --- a/bus/inputcontext.c +++ b/bus/inputcontext.c @@ -2,7 +2,7 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2014 Peng Huang - * Copyright (C) 2015-2017 Takao Fujiwara + * Copyright (C) 2015-2018 Takao Fujiwara * Copyright (C) 2008-2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -1148,6 +1148,20 @@ _ic_set_surrounding_text (BusInputContext *context, g_dbus_method_invocation_return_value (invocation, NULL); } +/* + * Since IBusService is inherited by IBusImpl, this method cannot be + * applied to IBusServiceClass.method_call() directly but can be in + * each child class.method_call(). + */ +static gboolean +bus_input_context_service_authorized_method (IBusService *service, + GDBusConnection *connection) +{ + if (ibus_service_get_connection (service) == connection) + return TRUE; + return FALSE; +} + /** * bus_input_context_service_method_call: * @@ -1197,6 +1211,10 @@ bus_input_context_service_method_call (IBusService *service, }; gint i; + + if (!bus_input_context_service_authorized_method (service, connection)) + return; + for (i = 0; i < G_N_ELEMENTS (methods); i++) { if (g_strcmp0 (method_name, methods[i].method_name) == 0) { methods[i].method_callback ((BusInputContext *)service, parameters, invocation); @@ -1270,6 +1288,9 @@ bus_input_context_service_set_property (IBusService *service, error); } + if (!bus_input_context_service_authorized_method (service, connection)) + return FALSE; + if (g_strcmp0 (property_name, "ContentType") == 0) { BusInputContext *context = (BusInputContext *) service; _ic_set_content_type (context, value); @@ -1279,6 +1300,7 @@ bus_input_context_service_set_property (IBusService *service, g_return_val_if_reached (FALSE); } + gboolean bus_input_context_has_focus (BusInputContext *context) { diff --git a/src/ibusengine.c b/src/ibusengine.c index b2a8022a..da648d11 100644 --- a/src/ibusengine.c +++ b/src/ibusengine.c @@ -2,7 +2,8 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2008-2013 Red Hat, Inc. + * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2008-2018 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 @@ -851,6 +852,15 @@ ibus_engine_get_property (IBusEngine *engine, } } +static gboolean +ibus_engine_service_authorized_method (IBusService *service, + GDBusConnection *connection) +{ + if (ibus_service_get_connection (service) == connection) + return TRUE; + return FALSE; +} + static void ibus_engine_service_method_call (IBusService *service, GDBusConnection *connection, @@ -876,6 +886,9 @@ ibus_engine_service_method_call (IBusService *service, return; } + if (!ibus_engine_service_authorized_method (service, connection)) + return; + if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) { guint keyval, keycode, state; gboolean retval = FALSE; @@ -1085,6 +1098,9 @@ ibus_engine_service_set_property (IBusService *service, error); } + if (!ibus_engine_service_authorized_method (service, connection)) + return FALSE; + if (g_strcmp0 (property_name, "ContentType") == 0) { guint purpose = 0; guint hints = 0; diff --git a/src/ibuspanelservice.c b/src/ibuspanelservice.c index 468aa324..33949fa1 100644 --- a/src/ibuspanelservice.c +++ b/src/ibuspanelservice.c @@ -3,7 +3,7 @@ /* ibus - The Input Bus * Copyright (c) 2009-2014 Google Inc. All rights reserved. * Copyright (C) 2010-2014 Peng Huang - * Copyright (C) 2017 Takao Fujiwara + * Copyright (C) 2017-2018 Takao Fujiwara * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -936,6 +936,15 @@ _g_object_unref_if_floating (gpointer instance) g_object_unref (instance); } +static gboolean +ibus_panel_service_service_authorized_method (IBusService *service, + GDBusConnection *connection) +{ + if (ibus_service_get_connection (service) == connection) + return TRUE; + return FALSE; +} + static void ibus_panel_service_service_method_call (IBusService *service, GDBusConnection *connection, @@ -961,6 +970,9 @@ ibus_panel_service_service_method_call (IBusService *service, return; } + if (!ibus_panel_service_service_authorized_method (service, connection)) + return; + if (g_strcmp0 (method_name, "UpdatePreeditText") == 0) { GVariant *variant = NULL; guint cursor = 0; -- 2.14.3 From e17c99859d06ab75326730e45072e1061f7d87c7 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 29 Jan 2018 16:50:07 +0900 Subject: [PATCH] Implement Unicode choice on Emojier BUG=https://github.com/ibus/ibus/issues/1922 Review URL: https://codereview.appspot.com/340190043 --- configure.ac | 41 +- po/POTFILES.in | 1 + src/Makefile.am | 55 ++- src/emoji-parser.c | 3 +- src/ibus.h | 4 +- src/ibusunicode.c | 1069 +++++++++++++++++++++++++++++++++++++++++ src/ibusunicode.h | 299 ++++++++++++ src/ibusunicodegen.h | 1151 +++++++++++++++++++++++++++++++++++++++++++++ src/unicode-parser.c | 502 ++++++++++++++++++++ ui/gtk3/emojier.vala | 550 +++++++++++++++++++--- ui/gtk3/emojierapp.vala | 2 + ui/gtk3/ibusemojidialog.h | 9 +- ui/gtk3/panel.vala | 3 +- 13 files changed, 3613 insertions(+), 76 deletions(-) create mode 100644 src/ibusunicode.c create mode 100644 src/ibusunicode.h create mode 100644 src/ibusunicodegen.h create mode 100644 src/unicode-parser.c diff --git a/configure.ac b/configure.ac index 4789328e..bd41069b 100644 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,8 @@ # ibus - The Input Bus # # Copyright (c) 2007-2016 Peng Huang -# Copyright (c) 2015-2017 Takao Fujiwara -# Copyright (c) 2007-2017 Red Hat, Inc. +# Copyright (c) 2015-2018 Takao Fujiwara +# Copyright (c) 2007-2018 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 @@ -653,6 +653,41 @@ https://github.com/fujiwarat/cldr-emoji-annotation) enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)" fi +# --disable-unicode-dict option. +AC_ARG_ENABLE(unicode-dict, + AS_HELP_STRING([--disable-unicode-dict], + [Do not build Unicode dict files]), + [enable_unicode_dict=$enableval], + [enable_unicode_dict=yes] +) +AM_CONDITIONAL([ENABLE_UNICODE_DICT], [test x"$enable_unicode_dict" = x"yes"]) + +AC_ARG_WITH(ucd-dir, + AS_HELP_STRING([--with-ucd-dir[=DIR]], + [Set the directory of UCD (Unicode Character Database) files. + (default: "/usr/share/unicode/ucd")]), + UCD_DIR=$with_emoji_annotation_dir, + UCD_DIR="/usr/share/unicode/ucd" +) +AC_SUBST(UCD_DIR) + +if test x"$enable_unicode_dict" = x"yes"; then + if test ! -f $UCD_DIR/NamesList.txt ; then + AC_MSG_ERROR(Not found $UCD_DIR/NamesList.txt. You can get \ +the UCD files from https://www.unicode.org/Public/UNIDATA/) + elif test ! -f $UCD_DIR/Blocks.txt ; then + AC_MSG_ERROR(Not found $UCD_DIR/Blocks.txt. You can get \ +the UCD files from https://www.unicode.org/Public/UNIDATA/) + else + # POSIX SHELL has no ${FOO:0:1} + head=`echo "$UCD_DIR" | cut -c1`; + if test $head != "/" ; then + UCD_DIR=`realpath "$UCD_DIR"` + fi + fi + enable_unicode_dict="yes (enabled, use --disable-unicode-dict to disable)" +fi + # Check iso-codes. PKG_CHECK_MODULES(ISOCODES, [ iso-codes @@ -743,6 +778,8 @@ Build options: Enable Emoji dict $enable_emoji_dict Unicode Emoji directory $UNICODE_EMOJI_DIR CLDR annotation directory $EMOJI_ANNOTATION_DIR + Enable Unicode dict $enable_unicode_dict + UCD directory $UCD_DIR Run test cases $enable_tests ]) diff --git a/po/POTFILES.in b/po/POTFILES.in index 00f7c7f6..58d1e39d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -51,6 +51,7 @@ src/ibuspanelservice.c src/ibusproxy.c src/ibusregistry.c src/ibusservice.c +src/ibusunicodegen.h src/ibusutil.c src/keyname-table.h tools/main.vala diff --git a/src/Makefile.am b/src/Makefile.am index 303250f5..1ba418d8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ INTROSPECTION_COMPILER_ARGS = \ $(NULL) INTROSPECTION_GIRS = CLEANFILES = +noinst_PROGRAMS = # C preprocessor flags AM_CPPFLAGS = \ @@ -100,6 +101,7 @@ ibus_sources = \ ibusservice.c \ ibusshare.c \ ibustext.c \ + ibusunicode.c \ ibusutil.c \ ibusxml.c \ $(NULL) @@ -151,6 +153,7 @@ ibus_headers = \ ibusshare.h \ ibustext.h \ ibustypes.h \ + ibusunicode.h \ ibusutil.h \ ibusxml.h \ $(NULL) @@ -169,6 +172,7 @@ ibus_private_headers = \ ibusemojigen.h \ ibusenginesimpleprivate.h \ ibusinternal.h \ + ibusunicodegen.h \ keyname-table.h \ $(NULL) noinst_HEADERS = \ @@ -241,7 +245,7 @@ dictdir = $(pkgdatadir)/dicts dict_DATA = dicts/emoji-en.dict LANG_FILES = $(basename $(notdir $(wildcard $(EMOJI_ANNOTATION_DIR)/*.xml))) -noinst_PROGRAMS = emoji-parser +noinst_PROGRAMS += emoji-parser dicts/emoji-en.dict: emoji-parser $(AM_V_at)if test x"$(LANG_FILES)" = x ; then \ @@ -325,12 +329,60 @@ clean-local: $(NULL) endif +if ENABLE_UNICODE_DICT +unicodedir = $(pkgdatadir)/dicts +unicode_DATA = dicts/unicode-names.dict dicts/unicode-blocks.dict +noinst_PROGRAMS += unicode-parser + +dicts/unicode-names.dict: unicode-parser + $(AM_V_at)input_file="$(UCD_DIR)/NamesList.txt"; \ + if test ! -f "$$input_file" ; then \ + echo "WARNING: Not found $$input_file" 1>&2; \ + else \ + $(builddir)/unicode-parser \ + --input-names-list $$input_file \ + --output-names-list $@; \ + echo "Generated $@"; \ + fi; + +dicts/unicode-blocks.dict: unicode-parser + $(AM_V_at)input_file="$(UCD_DIR)/Blocks.txt"; \ + if test ! -f "$$input_file" ; then \ + echo "WARNING: Not found $$input_file" 1>&2; \ + else \ + $(builddir)/unicode-parser \ + --input-blocks $$input_file \ + --output-blocks-trans ibusunicodegen.h \ + --output-blocks $@; \ + echo "Generated $@"; \ + fi; + +ibusunicodegen.h: dicts/unicode-blocks.dict + $(NULL) + +unicode_parser_SOURCES = \ + unicode-parser.c \ + $(NULL) +unicode_parser_CFLAGS = \ + $(GLIB2_CFLAGS) \ + $(NULL) +unicode_parser_LDADD = \ + $(GLIB2_LIBS) \ + $(libibus) \ + $(NULL) + +clean-local: + -rm -rf dicts + $(NULL) +endif + EXTRA_DIST = \ emoji-parser.c \ ibusversion.h.in \ ibusmarshalers.list \ ibusenumtypes.h.template \ ibusenumtypes.c.template \ + unicode-parser.c \ $(NULL) CLEANFILES += \ @@ -341,6 +393,7 @@ CLEANFILES += \ DISTCLEANFILES = \ ibusemojigen.h \ + ibusunicodegen.h \ ibusversion.h \ $(NULL) diff --git a/src/emoji-parser.c b/src/emoji-parser.c index fe3e4ef8..0f7c8cfb 100644 --- a/src/emoji-parser.c +++ b/src/emoji-parser.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* vim:set et sts=4: */ /* ibus - The Input Bus - * Copyright (C) 2016-2017 Takao Fujiwara + * Copyright (C) 2016-2018 Takao Fujiwara * Copyright (C) 2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -1126,6 +1126,7 @@ category_file_save (const gchar *filename, if (!g_file_get_contents (__FILE__, &content, &length, &error)) { g_warning ("Failed to load %s: %s", __FILE__, error->message); g_clear_pointer (&error, g_error_free); + return; } buff = g_string_new (NULL); p = content; diff --git a/src/ibus.h b/src/ibus.h index c6cf58cf..8011729f 100644 --- a/src/ibus.h +++ b/src/ibus.h @@ -2,7 +2,8 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2008-2013 Red Hat, Inc. + * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2008-2018 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 @@ -57,6 +58,7 @@ #include #include #include +#include #ifndef IBUS_DISABLE_DEPRECATED #include diff --git a/src/ibusunicode.c b/src/ibusunicode.c new file mode 100644 index 00000000..8559819d --- /dev/null +++ b/src/ibusunicode.c @@ -0,0 +1,1069 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* vim:set et sts=4: */ +/* bus - The Input Bus + * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2018 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 + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "ibusinternal.h" +#include "ibuserror.h" +#include "ibusunicode.h" + +#define IBUS_UNICODE_DATA_MAGIC "IBusUnicodeData" +#define IBUS_UNICODE_BLOCK_MAGIC "IBusUnicodeBlock" +#define IBUS_UNICODE_DATA_VERSION (1) +#define IBUS_UNICODE_DESERIALIZE_SIGNALL_STR \ + "deserialize-unicode" + +enum { + PROP_0 = 0, + PROP_CODE, + PROP_NAME, + PROP_ALIAS, + PROP_BLOCK_NAME, + PROP_START, + PROP_END +}; + +struct _IBusUnicodeDataPrivate { + gunichar code; + gchar *name; + gchar *alias; + gchar *block_name; +}; + +struct _IBusUnicodeBlockPrivate { + gunichar start; + gunichar end; + gchar *name; +}; + +typedef struct { + IBusUnicodeDataLoadAsyncFinish callback; + gpointer user_data; +} IBusUnicodeDataLoadData; + +#define IBUS_UNICODE_DATA_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + IBUS_TYPE_UNICODE_DATA, \ + IBusUnicodeDataPrivate)) +#define IBUS_UNICODE_BLOCK_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + IBUS_TYPE_UNICODE_BLOCK, \ + IBusUnicodeBlockPrivate)) + +/* functions prototype */ +static void ibus_unicode_data_set_property (IBusUnicodeData *unicode, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ibus_unicode_data_get_property (IBusUnicodeData *unicode, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void ibus_unicode_data_destroy (IBusUnicodeData *unicode); +static gboolean ibus_unicode_data_serialize (IBusUnicodeData *unicode, + GVariantBuilder *builder); +static gint ibus_unicode_data_deserialize (IBusUnicodeData *unicode, + GVariant *variant); +static gboolean ibus_unicode_data_copy (IBusUnicodeData *dest, + const IBusUnicodeData *src); +static void ibus_unicode_block_set_property + (IBusUnicodeBlock *block, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ibus_unicode_block_get_property + (IBusUnicodeBlock *block, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void ibus_unicode_block_destroy (IBusUnicodeBlock *block); +static gboolean ibus_unicode_block_serialize (IBusUnicodeBlock *block, + GVariantBuilder *builder); +static gint ibus_unicode_block_deserialize (IBusUnicodeBlock *block, + GVariant *variant); +static gboolean ibus_unicode_block_copy (IBusUnicodeBlock *dest, + const IBusUnicodeBlock *src); + +G_DEFINE_TYPE (IBusUnicodeData, ibus_unicode_data, IBUS_TYPE_SERIALIZABLE) +G_DEFINE_TYPE (IBusUnicodeBlock, ibus_unicode_block, IBUS_TYPE_SERIALIZABLE) + +static void +ibus_unicode_data_class_init (IBusUnicodeDataClass *class) +{ + IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class); + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); + + object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy; + gobject_class->set_property = + (GObjectSetPropertyFunc) ibus_unicode_data_set_property; + gobject_class->get_property = + (GObjectGetPropertyFunc) ibus_unicode_data_get_property; + serializable_class->serialize = + (IBusSerializableSerializeFunc) ibus_unicode_data_serialize; + serializable_class->deserialize = + (IBusSerializableDeserializeFunc) ibus_unicode_data_deserialize; + serializable_class->copy = + (IBusSerializableCopyFunc) ibus_unicode_data_copy; + + g_type_class_add_private (class, sizeof (IBusUnicodeDataPrivate)); + + /* install properties */ + /** + * IBusUnicodeData:code: + * + * The Uniode code point + */ + g_object_class_install_property (gobject_class, + PROP_CODE, + g_param_spec_unichar ("code", + "code point", + "The Unicode code point", + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + + /** + * IBusUnicodeData:name: + * + * The Uniode name + */ + g_object_class_install_property (gobject_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "The Unicode name", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /** + * IBusUnicodeData:alias: + * + * The Uniode alias name + */ + g_object_class_install_property (gobject_class, + PROP_ALIAS, + g_param_spec_string ("alias", + "alias name", + "The Unicode alias name", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /** + * IBusUnicodeData:block-name: + * + * The Uniode block name + */ + g_object_class_install_property (gobject_class, + PROP_BLOCK_NAME, + g_param_spec_string ("block-name", + "block name", + "The Unicode block name", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +} + +static void +ibus_unicode_data_init (IBusUnicodeData *unicode) +{ + unicode->priv = IBUS_UNICODE_DATA_GET_PRIVATE (unicode); +} + +static void +ibus_unicode_data_destroy (IBusUnicodeData *unicode) +{ + g_clear_pointer (&unicode->priv->name, g_free); + g_clear_pointer (&unicode->priv->alias, g_free); + g_clear_pointer (&unicode->priv->block_name, g_free); + + IBUS_OBJECT_CLASS (ibus_unicode_data_parent_class)-> + destroy (IBUS_OBJECT (unicode)); +} + +static void +ibus_unicode_data_set_property (IBusUnicodeData *unicode, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_CODE: + g_assert (unicode->priv->code == 0); + unicode->priv->code = g_value_get_uint (value); + break; + case PROP_NAME: + g_assert (unicode->priv->name == NULL); + unicode->priv->name = g_value_dup_string (value); + break; + case PROP_ALIAS: + g_assert (unicode->priv->alias == NULL); + unicode->priv->alias = g_value_dup_string (value); + break; + case PROP_BLOCK_NAME: + g_free (unicode->priv->block_name); + unicode->priv->block_name = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (unicode, prop_id, pspec); + } +} + +static void +ibus_unicode_data_get_property (IBusUnicodeData *unicode, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_CODE: + g_value_set_uint (value, ibus_unicode_data_get_code (unicode)); + break; + case PROP_NAME: + g_value_set_string (value, ibus_unicode_data_get_name (unicode)); + break; + case PROP_ALIAS: + g_value_set_string (value, ibus_unicode_data_get_alias (unicode)); + break; + case PROP_BLOCK_NAME: + g_value_set_string (value, ibus_unicode_data_get_block_name (unicode)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (unicode, prop_id, pspec); + } +} + +static gboolean +ibus_unicode_data_serialize (IBusUnicodeData *unicode, + GVariantBuilder *builder) +{ + gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)-> + serialize ((IBusSerializable *)unicode, builder); + g_return_val_if_fail (retval, FALSE); + +#define NOTNULL(s) ((s) != NULL ? (s) : "") + /* If you will add a new property, you can append it at the end and + * you should not change the serialized order of name, longname, + * description, ... because the order is also used in other applications + * likes ibus-qt. */ + g_variant_builder_add (builder, "u", unicode->priv->code); + g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->name)); + g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->alias)); + /* Use IBusUnicodeBlock for memory usage. + g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->block_name)); + */ +#undef NOTNULL + return TRUE; +} + +static gint +ibus_unicode_data_deserialize (IBusUnicodeData *unicode, + GVariant *variant) +{ + gint retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)-> + deserialize ((IBusSerializable *)unicode, variant); + g_return_val_if_fail (retval, 0); + + /* If you will add a new property, you can append it at the end and + * you should not change the serialized order of name, longname, + * description, ... because the order is also used in other applications + * likes ibus-qt. */ + g_variant_get_child (variant, retval++, "u", &unicode->priv->code); + ibus_g_variant_get_child_string (variant, retval++, + &unicode->priv->name); + ibus_g_variant_get_child_string (variant, retval++, + &unicode->priv->alias); + /* Use IBusUnicodeBlock for memory usage. + ibus_g_variant_get_child_string (variant, retval++, + &unicode->priv->block_name); + */ + return retval; +} + +static gboolean +ibus_unicode_data_copy (IBusUnicodeData *dest, + const IBusUnicodeData *src) +{ + gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)-> + copy ((IBusSerializable *)dest, + (IBusSerializable *)src); + g_return_val_if_fail (retval, FALSE); + + dest->priv->code = src->priv->code; + dest->priv->name = g_strdup (src->priv->name); + dest->priv->alias = g_strdup (src->priv->alias); + dest->priv->block_name = g_strdup (src->priv->block_name); + return TRUE; +} + +IBusUnicodeData * +ibus_unicode_data_new (const gchar *first_property_name, ...) +{ + va_list var_args; + IBusUnicodeData *unicode; + + g_assert (first_property_name != NULL); + va_start (var_args, first_property_name); + unicode = (IBusUnicodeData *) g_object_new_valist (IBUS_TYPE_UNICODE_DATA, + first_property_name, + var_args); + va_end (var_args); + /* code is required. Other properties are set in class_init by default. */ + g_assert (unicode->priv->name != NULL); + g_assert (unicode->priv->alias != NULL); + g_assert (unicode->priv->block_name != NULL); + return unicode; +} + +gunichar +ibus_unicode_data_get_code (IBusUnicodeData *unicode) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), G_MAXUINT32); + + return unicode->priv->code; +} + +const gchar * +ibus_unicode_data_get_name (IBusUnicodeData *unicode) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), ""); + + return unicode->priv->name; +} + +const gchar * +ibus_unicode_data_get_alias (IBusUnicodeData *unicode) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), ""); + + return unicode->priv->alias; +} + +const gchar * +ibus_unicode_data_get_block_name (IBusUnicodeData *unicode) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), ""); + + return unicode->priv->block_name; +} + +void +ibus_unicode_data_set_block_name (IBusUnicodeData *unicode, + const gchar *block_name) +{ + g_return_if_fail (IBUS_IS_UNICODE_DATA (unicode)); + + g_free (unicode->priv->block_name); + unicode->priv->block_name = g_strdup (block_name); +} + +static void +variant_foreach_add_unicode (IBusUnicodeData *unicode, + GVariantBuilder *builder) +{ + g_variant_builder_add ( + builder, "v", + ibus_serializable_serialize (IBUS_SERIALIZABLE (unicode))); +} + +static GVariant * +ibus_unicode_data_list_serialize (GSList *list) +{ + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("av")); + g_slist_foreach (list, (GFunc) variant_foreach_add_unicode, &builder); + return g_variant_builder_end (&builder); +} + +static GSList * +ibus_unicode_data_list_deserialize (GVariant *variant, + GObject *source_object) +{ + GSList *list = NULL; + GVariantIter iter; + GVariant *unicode_variant = NULL; + gsize i, size; + gboolean has_signal = FALSE; + + if (G_IS_OBJECT (source_object)) { + has_signal = g_signal_lookup ( + IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, + G_OBJECT_TYPE (source_object)); + if (!has_signal) { + const gchar type_name = g_type_name (source_object); + g_warning ("GObject %s does not have the signal \"%s\"", + type_name ? type_name : "(null)", + IBUS_UNICODE_DESERIALIZE_SIGNALL_STR); + } + } + g_variant_iter_init (&iter, variant); + size = g_variant_iter_n_children (&iter); + i = 0; + while (g_variant_iter_loop (&iter, "v", &unicode_variant)) { + IBusUnicodeData *data = + IBUS_UNICODE_DATA (ibus_serializable_deserialize ( + unicode_variant)); + list = g_slist_append (list, data); + g_clear_pointer (&unicode_variant, g_variant_unref); + if (has_signal && (i == 0 || ((i + 1) % 100) == 0)) { + g_signal_emit_by_name (source_object, + IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, + i + 1, size); + } + i++; + } + if (has_signal && (i != 1 && (i % 100) != 0)) { + g_signal_emit_by_name (source_object, + IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, + i, size); + } + + return list; +} + +void +ibus_unicode_data_save (const gchar *path, + GSList *list) +{ + GVariant *variant; + const gchar *header = IBUS_UNICODE_DATA_MAGIC; + const guint16 version = IBUS_UNICODE_DATA_VERSION; + const gchar *contents; + gsize length; + gchar *dir; + GStatBuf buf = { 0, }; + GError *error = NULL; + + g_return_if_fail (path != NULL); + g_return_if_fail (list != NULL); + if (list->data == NULL) { + g_warning ("Failed to save IBus Unicode data: Need a list data."); + return; + } + + variant = g_variant_new ("(sqv)", + header, + version, + ibus_unicode_data_list_serialize (list)); + + contents = g_variant_get_data (variant); + length = g_variant_get_size (variant); + + dir = g_path_get_dirname (path); + if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { + g_mkdir_with_parents (dir, 0777); + } + g_free (dir); + if (!g_file_set_contents (path, contents, length, &error)) { + g_warning ("Failed to save Unicode dict %s: %s", path, error->message); + g_error_free (error); + } + + g_variant_unref (variant); +} + +static GSList * +ibus_unicode_data_load_with_error (const gchar *path, + GObject *source_object, + GError **error) +{ + gchar *contents = NULL; + gsize length = 0; + GVariant *variant_table = NULL; + GVariant *variant = NULL; + const gchar *header = NULL; + guint16 version = 0; + GSList *retval = NULL; + + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_set_error (error, + IBUS_ERROR, + IBUS_ERROR_FAILED, + "Unicode dict does not exist: %s", path); + goto out_load_cache; + } + + if (!g_file_get_contents (path, &contents, &length, 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_set_error (error, + IBUS_ERROR, + IBUS_ERROR_FAILED, + "cache table is broken."); + goto out_load_cache; + } + + g_variant_get (variant_table, "(&sq)", &header, &version); + + if (g_strcmp0 (header, IBUS_UNICODE_DATA_MAGIC) != 0) { + g_set_error (error, + IBUS_ERROR, + IBUS_ERROR_FAILED, + "cache is not IBusUnicodeData."); + goto out_load_cache; + } + + if (version > IBUS_UNICODE_DATA_VERSION) { + g_set_error (error, + IBUS_ERROR, + IBUS_ERROR_FAILED, + "cache version is different: %u != %u", + version, IBUS_UNICODE_DATA_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_set_error (error, + IBUS_ERROR, + IBUS_ERROR_FAILED, + "cache table is broken."); + goto out_load_cache; + } + + g_variant_get (variant_table, "(&sqv)", + NULL, + NULL, + &variant); + + if (variant == NULL) { + g_set_error (error, + IBUS_ERROR, + IBUS_ERROR_FAILED, + "cache dict is broken."); + goto out_load_cache; + } + + retval = ibus_unicode_data_list_deserialize (variant, source_object); + +out_load_cache: + if (variant) + g_variant_unref (variant); + if (variant_table) + g_variant_unref (variant_table); + g_free (contents); + + return retval; +} + +GSList * +ibus_unicode_data_load (const gchar *path, + GObject *source_object) +{ + GError *error = NULL; + GSList *retval = ibus_unicode_data_load_with_error (path, + source_object, + &error); + + if (retval == NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + return retval; +} + +static void +ibus_unicode_data_load_async_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GSList *retval; + gchar *path = (gchar *)task_data; + GError *error = NULL; + + g_assert (path != NULL); + + retval = ibus_unicode_data_load_with_error (path, source_object, &error); + g_free (path); + if (retval == NULL) + g_task_return_error (task, error); + else + g_task_return_pointer (task, retval, NULL); + g_object_unref (task); +} + +static void +ibus_unicode_data_load_async_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + IBusUnicodeDataLoadData *data = (IBusUnicodeDataLoadData*)user_data; + GSList *list; + GError *error = NULL; + g_assert (data != NULL); + list = g_task_propagate_pointer (G_TASK (res), &error); + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + data->callback (NULL, data->user_data); + } else { + data->callback (list, data->user_data); + } + g_slice_free (IBusUnicodeDataLoadData, data); +} + +void +ibus_unicode_data_load_async (const gchar *path, + GObject *source_object, + GCancellable *cancellable, + IBusUnicodeDataLoadAsyncFinish + callback, + gpointer user_data) +{ + GTask *task; + IBusUnicodeDataLoadData *data; + + g_return_if_fail (path != NULL); + + data = g_slice_new0 (IBusUnicodeDataLoadData); + data->callback = callback; + data->user_data = user_data; + task = g_task_new (source_object, + cancellable, + ibus_unicode_data_load_async_done, + data); + g_task_set_source_tag (task, ibus_unicode_data_load_async); + g_task_set_task_data (task, g_strdup (path), NULL); + g_task_run_in_thread (task, ibus_unicode_data_load_async_thread); +} + +static void +ibus_unicode_block_class_init (IBusUnicodeBlockClass *class) +{ + IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class); + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); + + object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy; + gobject_class->set_property = + (GObjectSetPropertyFunc) ibus_unicode_block_set_property; + gobject_class->get_property = + (GObjectGetPropertyFunc) ibus_unicode_block_get_property; + serializable_class->serialize = + (IBusSerializableSerializeFunc) ibus_unicode_block_serialize; + serializable_class->deserialize = + (IBusSerializableDeserializeFunc) ibus_unicode_block_deserialize; + serializable_class->copy = + (IBusSerializableCopyFunc) ibus_unicode_block_copy; + + g_type_class_add_private (class, sizeof (IBusUnicodeBlockPrivate)); + + /* install properties */ + /** + * IBusUnicodeBlock:start: + * + * The Uniode start code point + */ + g_object_class_install_property (gobject_class, + PROP_START, + /* Cannot use g_param_spec_unichar() for the Unicode + * boundary values because the function checks + * if the value is a valid Unicode besides MAXUINT. + */ + g_param_spec_uint ("start", + "start code point", + "The Unicode start code point", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + + /** + * IBusUnicodeBlock:end: + * + * The Uniode end code point + */ + g_object_class_install_property (gobject_class, + PROP_END, + /* Cannot use g_param_spec_unichar() for the Unicode + * boundary values because the function checks + * if the value is a valid Unicode besides MAXUINT. + */ + g_param_spec_uint ("end", + "end code point", + "The Unicode end code point", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + + /** + * IBusUnicodeBlock:name: + * + * The Uniode block name + */ + g_object_class_install_property (gobject_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "The Unicode name", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +} + +static void +ibus_unicode_block_init (IBusUnicodeBlock *block) +{ + block->priv = IBUS_UNICODE_BLOCK_GET_PRIVATE (block); +} + +static void +ibus_unicode_block_destroy (IBusUnicodeBlock *block) +{ + g_clear_pointer (&block->priv->name, g_free); + + IBUS_OBJECT_CLASS (ibus_unicode_data_parent_class)-> + destroy (IBUS_OBJECT (block)); +} + +static void +ibus_unicode_block_set_property (IBusUnicodeBlock *block, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_START: + g_assert (block->priv->start == 0); + block->priv->start = g_value_get_uint (value); + break; + case PROP_END: + g_assert (block->priv->end == 0); + block->priv->end = g_value_get_uint (value); + break; + case PROP_NAME: + g_assert (block->priv->name == NULL); + block->priv->name = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (block, prop_id, pspec); + } +} + +static void +ibus_unicode_block_get_property (IBusUnicodeBlock *block, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_START: + g_value_set_uint (value, ibus_unicode_block_get_start (block)); + break; + case PROP_END: + g_value_set_uint (value, ibus_unicode_block_get_end (block)); + break; + case PROP_NAME: + g_value_set_string (value, ibus_unicode_block_get_name (block)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (block, prop_id, pspec); + } +} + +static gboolean +ibus_unicode_block_serialize (IBusUnicodeBlock *block, + GVariantBuilder *builder) +{ + gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)-> + serialize ((IBusSerializable *)block, builder); + g_return_val_if_fail (retval, FALSE); + +#define NOTNULL(s) ((s) != NULL ? (s) : "") + /* If you will add a new property, you can append it at the end and + * you should not change the serialized order of name, longname, + * description, ... because the order is also used in other applications + * likes ibus-qt. */ + g_variant_builder_add (builder, "u", block->priv->start); + g_variant_builder_add (builder, "u", block->priv->end); + g_variant_builder_add (builder, "s", NOTNULL (block->priv->name)); +#undef NOTNULL + return TRUE; +} + +static gint +ibus_unicode_block_deserialize (IBusUnicodeBlock *block, + GVariant *variant) +{ + gint retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)-> + deserialize ((IBusSerializable *)block, variant); + g_return_val_if_fail (retval, 0); + + /* If you will add a new property, you can append it at the end and + * you should not change the serialized order of name, longname, + * description, ... because the order is also used in other applications + * likes ibus-qt. */ + g_variant_get_child (variant, retval++, "u", &block->priv->start); + g_variant_get_child (variant, retval++, "u", &block->priv->end); + ibus_g_variant_get_child_string (variant, retval++, + &block->priv->name); + return retval; +} + +static gboolean +ibus_unicode_block_copy (IBusUnicodeBlock *dest, + const IBusUnicodeBlock *src) +{ + gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)-> + copy ((IBusSerializable *)dest, + (IBusSerializable *)src); + g_return_val_if_fail (retval, FALSE); + + dest->priv->start = src->priv->start; + dest->priv->end = src->priv->end; + dest->priv->name = g_strdup (src->priv->name); + return TRUE; +} + +IBusUnicodeBlock * +ibus_unicode_block_new (const gchar *first_property_name, ...) +{ + va_list var_args; + IBusUnicodeBlock *block; + + g_assert (first_property_name != NULL); + va_start (var_args, first_property_name); + block = (IBusUnicodeBlock *) g_object_new_valist (IBUS_TYPE_UNICODE_BLOCK, + first_property_name, + var_args); + va_end (var_args); + /* end is required. Other properties are set in class_init by default. */ + g_assert (block->priv->start != block->priv->end); + g_assert (block->priv->name != NULL); + return block; +} + +gunichar +ibus_unicode_block_get_start (IBusUnicodeBlock *block) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), G_MAXUINT32); + + return block->priv->start; +} + +gunichar +ibus_unicode_block_get_end (IBusUnicodeBlock *block) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), G_MAXUINT32); + + return block->priv->end; +} + +const gchar * +ibus_unicode_block_get_name (IBusUnicodeBlock *block) +{ + g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), ""); + + return block->priv->name; +} + +static void +variant_foreach_add_block (IBusUnicodeBlock *block, + GVariantBuilder *builder) +{ + g_variant_builder_add ( + builder, "v", + ibus_serializable_serialize (IBUS_SERIALIZABLE (block))); +} + +static GVariant * +ibus_unicode_block_list_serialize (GSList *list) +{ + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("av")); + g_slist_foreach (list, (GFunc) variant_foreach_add_block, &builder); + return g_variant_builder_end (&builder); +} + +static GSList * +ibus_unicode_block_list_deserialize (GVariant *variant) +{ + GSList *list = NULL; + GVariantIter iter; + GVariant *unicode_variant = NULL; + + g_variant_iter_init (&iter, variant); + while (g_variant_iter_loop (&iter, "v", &unicode_variant)) { + IBusUnicodeBlock *data = + IBUS_UNICODE_BLOCK (ibus_serializable_deserialize ( + unicode_variant)); + list = g_slist_append (list, data); + g_clear_pointer (&unicode_variant, g_variant_unref); + } + + return list; +} + +void +ibus_unicode_block_save (const gchar *path, + GSList *list) +{ + GVariant *variant; + const gchar *header = IBUS_UNICODE_BLOCK_MAGIC; + const guint16 version = IBUS_UNICODE_DATA_VERSION; + const gchar *contents; + gsize length; + gchar *dir; + GStatBuf buf = { 0, }; + GError *error = NULL; + + g_return_if_fail (path != NULL); + g_return_if_fail (list != NULL); + if (list->data == NULL) { + g_warning ("Failed to save IBus Unicode block: Need a list data."); + return; + } + + variant = g_variant_new ("(sqv)", + header, + version, + ibus_unicode_block_list_serialize (list)); + + contents = g_variant_get_data (variant); + length = g_variant_get_size (variant); + + dir = g_path_get_dirname (path); + if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { + g_mkdir_with_parents (dir, 0777); + } + g_free (dir); + if (!g_file_set_contents (path, contents, length, &error)) { + g_warning ("Failed to save Unicode dict %s: %s", path, error->message); + g_error_free (error); + } + + g_variant_unref (variant); +} + +GSList * +ibus_unicode_block_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; + GSList *retval = NULL; + + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_warning ("Unicode 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_UNICODE_BLOCK_MAGIC) != 0) { + g_warning ("cache is not IBusUnicodeBlock."); + goto out_load_cache; + } + + if (version > IBUS_UNICODE_DATA_VERSION) { + g_warning ("cache version is different: %u != %u", + version, IBUS_UNICODE_DATA_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_unicode_block_list_deserialize (variant); + +out_load_cache: + if (variant) + g_variant_unref (variant); + if (variant_table) + g_variant_unref (variant_table); + g_free (contents); + + return retval; +} + diff --git a/src/ibusunicode.h b/src/ibusunicode.h new file mode 100644 index 00000000..99de9451 --- /dev/null +++ b/src/ibusunicode.h @@ -0,0 +1,299 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* vim:set et sts=4: */ +/* bus - The Input Bus + * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2018 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 + */ + +#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION) +#error "Only can be included directly" +#endif + +#ifndef __IBUS_UNICODE_H_ +#define __IBUS_UNICODE_H_ + +/** + * SECTION: ibusunicode + * @short_description: unicode utility. + * @stability: Unstable + * + * miscellaneous unicode APIs. + */ + +#include +#include "ibusserializable.h" + +/* + * Type macros. + */ +/* define GOBJECT macros */ +#define IBUS_TYPE_UNICODE_DATA (ibus_unicode_data_get_type ()) +#define IBUS_UNICODE_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + IBUS_TYPE_UNICODE_DATA, IBusUnicodeData)) +#define IBUS_UNICODE_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ + IBUS_TYPE_UNICODE_DATA, \ + IBusUnicodeDataClass)) +#define IBUS_IS_UNICODE_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + IBUS_TYPE_UNICODE_DATA)) +#define IBUS_TYPE_UNICODE_BLOCK (ibus_unicode_block_get_type ()) +#define IBUS_UNICODE_BLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + IBUS_TYPE_UNICODE_BLOCK, \ + IBusUnicodeBlock)) +#define IBUS_UNICODE_BLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ + IBUS_TYPE_UNICODE_BLOCK, \ + IBusUnicodeBlockClass)) +#define IBUS_IS_UNICODE_BLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + IBUS_TYPE_UNICODE_BLOCK)) + + +G_BEGIN_DECLS + +typedef struct _IBusUnicodeData IBusUnicodeData; +typedef struct _IBusUnicodeDataPrivate IBusUnicodeDataPrivate; +typedef struct _IBusUnicodeDataClass IBusUnicodeDataClass; +typedef struct _IBusUnicodeBlock IBusUnicodeBlock; +typedef struct _IBusUnicodeBlockPrivate IBusUnicodeBlockPrivate; +typedef struct _IBusUnicodeBlockClass IBusUnicodeBlockClass; + +/** + * IBusUnicodeDataLoadAsyncFinish: + * @data_list: (transfer full) (element-type IBusUnicodeData): + * + * This callback can receive the list of #IBusUnicodeData. + */ +typedef void (*IBusUnicodeDataLoadAsyncFinish) (GSList *data_list, + gpointer user_data); + +/** + * IBusUnicodeData: + * + * Unicode data likes code, name, alias, block-name. + * You can get extended values with g_object_get_properties. + */ +struct _IBusUnicodeData { + IBusSerializable parent; + /* instance members */ + + /*< public >*/ + /*< private >*/ + IBusUnicodeDataPrivate *priv; +}; + +struct _IBusUnicodeDataClass { + IBusSerializableClass parent; + /* class members */ +}; + +struct _IBusUnicodeBlock { + IBusSerializable parent; + /* instance members */ + + /*< public >*/ + /*< private >*/ + IBusUnicodeBlockPrivate *priv; +}; + +struct _IBusUnicodeBlockClass { + IBusSerializableClass parent; + /* class members */ +}; + +GType ibus_unicode_data_get_type (void); +GType ibus_unicode_block_get_type (void); + +/** + * ibus_unicode_data_new: + * @first_property_name: Name of the first property. + * @...: the NULL-terminated arguments of the properties and values. + * + * Creates a new #IBusUnicodeData. + * code property is required. e.g. + * ibus_unicode_data_new ("code", 0x3042, NULL) + * + * Returns: A newly allocated #IBusUnicodeData. + */ +IBusUnicodeData * ibus_unicode_data_new (const gchar *first_property_name, + ...); + +/** + * ibus_unicode_data_get_code: + * @unicode: An #IBusUnicodeData + * + * Gets the code point in #IBusUnicodeData. + * + * Returns: code property in #IBusUnicodeData + */ +gunichar ibus_unicode_data_get_code (IBusUnicodeData *unicode); + +/** + * ibus_unicode_data_get_name: + * @unicode: An #IBusUnicodeData + * + * Gets the name in #IBusUnicodeData. It should not be freed. + * + * Returns: name property in #IBusUnicodeData + */ +const gchar * ibus_unicode_data_get_name (IBusUnicodeData *unicode); + +/** + * ibus_unicode_data_get_alias: + * @unicode: An #IBusUnicodeData + * + * Gets the alias in #IBusUnicodeData. It should not be freed. + * + * Returns: alias property in #IBusUnicodeData + */ +const gchar * ibus_unicode_data_get_alias (IBusUnicodeData *unicode); + +/** + * ibus_unicode_data_get_block_name: + * @unicode: An #IBusUnicodeData + * + * Gets the block name in #IBusUnicodeData. It should not be freed. + * + * Returns: block-name property in #IBusUnicodeData + */ +const gchar * ibus_unicode_data_get_block_name + (IBusUnicodeData *unicode); + +/** + * ibus_unicode_data_set_block_name: + * @unicode: An #IBusUnicodeData + * @block_name: A block name + * + * Sets the block name in #IBusUnicodeData. + */ +void ibus_unicode_data_set_block_name + (IBusUnicodeData *unicode, + const gchar *block_name); + +/** + * ibus_unicode_data_save: + * @path: A path of the saved Unicode data. + * @list: (element-type IBusUnicodeData) (transfer none): A list of unicode + * data. + * + * Save the list of #IBusUnicodeData to the cache file. + */ +void ibus_unicode_data_save (const gchar *path, + GSList *list); + +/** + * ibus_unicode_data_load: + * @path: A path of the saved dictionary file. + * @object: (nullable): If the #GObject has "unicode-deserialize-progress" + * signal, this function will emit (the number of desrialized + * #IBusUnicodeData, * the total number of #IBusUnicodeData) of uint values + * with that signal by 100 times. Otherwise %NULL. + * + * Returns: (element-type IBusUnicodeData) (transfer container): + * An #IBusUnicodeData list loaded from the saved cache file. + */ +GSList * ibus_unicode_data_load (const gchar *path, + GObject *object); + +/** + * ibus_unicode_data_load_async: + * @path: A path of the saved dictionary file. + * @object: (nullable): If the #GObject has "unicode-deserialize-progress" + * signal, this function will emit (the number of desrialized + * #IBusUnicodeData, * the total number of #IBusUnicodeData) of uint values + * with that signal by 100 times. Otherwise %NULL. + * @cancellable: cancellable. + * @callback: (scope notified): IBusUnicodeDataLoadAsyncFinish. + * @user_data: User data. + * + * IBusUnicodeDataLoadAsyncFinish can receive the list of #IBusUnicodeData. + */ +void ibus_unicode_data_load_async + (const gchar *path, + GObject *object, + GCancellable *cancellable, + IBusUnicodeDataLoadAsyncFinish + callback, + gpointer user_data); + +/** + * ibus_unicode_block_new: + * @first_property_name: Name of the first property. + * @...: the NULL-terminated arguments of the properties and values. + * + * Creates a new #IBusUnicodeBlock. + * block property is required. e.g. + * ibus_unicode_block_new ("start", 0x0000, "end", "0x007f", "name", "basic", + * NULL) + * + * Returns: A newly allocated #IBusUnicodeBlock. + */ +IBusUnicodeBlock *ibus_unicode_block_new (const gchar *first_property_name, + ...); + +/** + * ibus_unicode_block_get_start: + * @block: An #IBusUnicodeData + * + * Gets the start code point in #IBusUnicodeBlock. + * + * Returns: start property in #IBusUnicodeBlock + */ +gunichar ibus_unicode_block_get_start + (IBusUnicodeBlock *block); + +/** + * ibus_unicode_block_get_end: + * @block: An #IBusUnicodeData + * + * Gets the end code point in #IBusUnicodeBlock. + * + * Returns: end property in #IBusUnicodeBlock + */ +gunichar ibus_unicode_block_get_end + (IBusUnicodeBlock *block); + +/** + * ibus_unicode_block_get_name: + * @block: An #IBusUnicodeBlock + * + * Gets the name in #IBusUnicodeBlock. It should not be freed. + * + * Returns: name property in #IBusUnicodeBlock + */ +const gchar * ibus_unicode_block_get_name (IBusUnicodeBlock *block); + +/** + * ibus_unicode_block_save: + * @path: A path of the saved Unicode block. + * @list: (element-type IBusUnicodeBlock) (transfer none): A list of unicode + * block. + * + * Save the list of #IBusUnicodeBlock to the cache file. + */ +void ibus_unicode_block_save (const gchar *path, + GSList *list); + +/** + * ibus_unicode_block_load: + * @path: A path of the saved dictionary file. + * + * Returns: (element-type IBusUnicodeBlock) (transfer container): + * An #IBusUnicodeBlock list loaded from the saved cache file. + */ +GSList * ibus_unicode_block_load (const gchar *path); + +G_END_DECLS +#endif diff --git a/src/ibusunicodegen.h b/src/ibusunicodegen.h new file mode 100644 index 00000000..c613b81b --- /dev/null +++ b/src/ibusunicodegen.h @@ -0,0 +1,1151 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* vim:set et sts=4: */ +/* ibus - The Input Bus + * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2018 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 + */ + + +/* This file is generated by unicode-parser.c. */ +include + +#ifndef __IBUS_UNICODE_GEN_H_ +#define __IBUS_UNICODE_GEN_H_ +const static char *unicode_blocks[] = { + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Basic Latin"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin-1 Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin Extended-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("IPA Extensions"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Spacing Modifier Letters"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Combining Diacritical Marks"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Greek and Coptic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cyrillic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cyrillic Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Armenian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hebrew"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arabic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Syriac"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arabic Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Thaana"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("NKo"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Samaritan"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mandaic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Syriac Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arabic Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Devanagari"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bengali"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Gurmukhi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Gujarati"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Oriya"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tamil"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Telugu"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kannada"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Malayalam"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sinhala"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Thai"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Lao"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tibetan"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Myanmar"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Georgian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hangul Jamo"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ethiopic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ethiopic Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cherokee"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Unified Canadian Aboriginal Syllabics"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ogham"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Runic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tagalog"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hanunoo"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Buhid"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tagbanwa"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Khmer"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mongolian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Unified Canadian Aboriginal Syllabics Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Limbu"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tai Le"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("New Tai Lue"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Khmer Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Buginese"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tai Tham"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Combining Diacritical Marks Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Balinese"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sundanese"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Batak"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Lepcha"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ol Chiki"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cyrillic Extended-C"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sundanese Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Vedic Extensions"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Phonetic Extensions"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Phonetic Extensions Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Combining Diacritical Marks Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin Extended Additional"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Greek Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("General Punctuation"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Superscripts and Subscripts"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Currency Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Combining Diacritical Marks for Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Letterlike Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Number Forms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arrows"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mathematical Operators"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miscellaneous Technical"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Control Pictures"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Optical Character Recognition"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Enclosed Alphanumerics"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Box Drawing"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Block Elements"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Geometric Shapes"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miscellaneous Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Dingbats"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miscellaneous Mathematical Symbols-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplemental Arrows-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Braille Patterns"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplemental Arrows-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miscellaneous Mathematical Symbols-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplemental Mathematical Operators"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miscellaneous Symbols and Arrows"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Glagolitic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin Extended-C"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Coptic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Georgian Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tifinagh"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ethiopic Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cyrillic Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplemental Punctuation"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Radicals Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kangxi Radicals"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ideographic Description Characters"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Symbols and Punctuation"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hiragana"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Katakana"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bopomofo"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hangul Compatibility Jamo"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kanbun"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bopomofo Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Strokes"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Katakana Phonetic Extensions"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Enclosed CJK Letters and Months"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Compatibility"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs Extension A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Yijing Hexagram Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Yi Syllables"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Yi Radicals"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Lisu"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Vai"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cyrillic Extended-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bamum"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Modifier Tone Letters"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin Extended-D"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Syloti Nagri"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Common Indic Number Forms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Phags-pa"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Saurashtra"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Devanagari Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kayah Li"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Rejang"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hangul Jamo Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Javanese"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Myanmar Extended-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cham"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Myanmar Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tai Viet"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Meetei Mayek Extensions"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ethiopic Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Latin Extended-E"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cherokee Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Meetei Mayek"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hangul Syllables"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hangul Jamo Extended-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("High Surrogates"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("High Private Use Surrogates"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Low Surrogates"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Private Use Area"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Compatibility Ideographs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Alphabetic Presentation Forms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arabic Presentation Forms-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Variation Selectors"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Vertical Forms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Combining Half Marks"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Compatibility Forms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Small Form Variants"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arabic Presentation Forms-B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Halfwidth and Fullwidth Forms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Specials"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Linear B Syllabary"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Linear B Ideograms"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Aegean Numbers"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ancient Greek Numbers"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ancient Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Phaistos Disc"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Lycian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Carian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Coptic Epact Numbers"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old Italic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Gothic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old Permic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ugaritic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old Persian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Deseret"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Shavian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Osmanya"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Osage"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Elbasan"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Caucasian Albanian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Linear A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cypriot Syllabary"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Imperial Aramaic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Palmyrene"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Nabataean"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Hatran"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Phoenician"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Lydian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Meroitic Hieroglyphs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Meroitic Cursive"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kharoshthi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old South Arabian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old North Arabian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Manichaean"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Avestan"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Inscriptional Parthian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Inscriptional Pahlavi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Psalter Pahlavi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old Turkic"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Old Hungarian"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Rumi Numeral Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Brahmi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kaithi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sora Sompeng"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Chakma"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mahajani"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sharada"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sinhala Archaic Numbers"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Khojki"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Multani"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Khudawadi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Grantha"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Newa"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tirhuta"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Siddham"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Modi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mongolian Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Takri"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ahom"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Warang Citi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Zanabazar Square"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Soyombo"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Pau Cin Hau"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bhaiksuki"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Marchen"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Masaram Gondi"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cuneiform"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Cuneiform Numbers and Punctuation"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Early Dynastic Cuneiform"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Egyptian Hieroglyphs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Anatolian Hieroglyphs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bamum Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mro"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Bassa Vah"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Pahawh Hmong"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miao"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ideographic Symbols and Punctuation"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tangut"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tangut Components"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kana Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Kana Extended-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Nushu"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Duployan"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Shorthand Format Controls"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Byzantine Musical Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Musical Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ancient Greek Musical Notation"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tai Xuan Jing Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Counting Rod Numerals"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mathematical Alphanumeric Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Sutton SignWriting"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Glagolitic Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mende Kikakui"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Adlam"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Arabic Mathematical Alphabetic Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Mahjong Tiles"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Domino Tiles"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Playing Cards"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Enclosed Alphanumeric Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Enclosed Ideographic Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Miscellaneous Symbols and Pictographs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Emoticons"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Ornamental Dingbats"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Transport and Map Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Alchemical Symbols"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Geometric Shapes Extended"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplemental Arrows-C"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplemental Symbols and Pictographs"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs Extension B"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs Extension C"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs Extension D"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs Extension E"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Unified Ideographs Extension F"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("CJK Compatibility Ideographs Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Tags"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Variation Selectors Supplement"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplementary Private Use Area-A"), + /* TRANSLATORS: You might refer the translations from gucharmap with + the following command: + msgmerge -C gucharmap.po ibus.po ibus.pot */ + N_("Supplementary Private Use Area-B"), +}; +#endif diff --git a/src/unicode-parser.c b/src/unicode-parser.c new file mode 100644 index 00000000..e98c6d5f --- /dev/null +++ b/src/unicode-parser.c @@ -0,0 +1,502 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* vim:set et sts=4: */ +/* ibus - The Input Bus + * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2018 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include +#endif + +#include "ibusunicode.h" + +#define NAMES_LIST_SUBJECT "The Unicode Standard" +#define BLOCKS_SUBJECT "Blocks-" + +/* This file has 21 lines about the license at the top of the file. */ +#define LICENSE_LINES 21 + +typedef enum +{ + UCD_NAMES_LIST, + UCD_BLOCKS +} UCDType; + +typedef struct _UnicodeData UnicodeData; +typedef struct _UnicodeDataIndex UnicodeDataIndex; + +struct _UnicodeData{ + gunichar code; + gchar *name; + gchar *alias; + gunichar start; + gunichar end; + GSList *list; +}; + +struct _UnicodeDataIndex { + gchar *index; + UnicodeData *data_list; +}; + +static gchar *unicode_version; + +static void +unicode_data_new_object (UnicodeData *data) +{ + g_return_if_fail (data != NULL); + if (!data->name) { + g_warning ("No name in U+%04X", data->code); + } + IBusUnicodeData *unicode = + ibus_unicode_data_new ("code", + data->code, + "name", + data->name ? g_strdup (data->name) + : g_strdup (""), + "alias", + data->alias ? g_strdup (data->alias) + : g_strdup (""), + NULL); + data->list = g_slist_append (data->list, unicode); +} + +static void +unicode_block_new_object (UnicodeData *data) +{ + g_return_if_fail (data != NULL); + if (!data->name) { + g_warning ("No name in U+%04X", data->start); + } + IBusUnicodeBlock *block = + ibus_unicode_block_new ("start", + data->start, + "end", + data->end, + "name", + data->name ? g_strdup (data->name) + : g_strdup (""), + NULL); + data->list = g_slist_append (data->list, block); +} + +static void +unicode_data_reset (UnicodeData *data) +{ + g_return_if_fail (data != NULL); + data->code = 0; + g_clear_pointer (&data->name, g_free); + g_clear_pointer (&data->alias, g_free); + data->start = 0; + data->end = 0; +} + +static gboolean +ucd_names_list_parse_comment (const gchar *line) +{ + static gboolean has_version = FALSE; + + if (has_version) + return TRUE; + if (strlen (line) > 4 && strncmp (line, "@@@", 3) == 0) { + gchar **elements = g_strsplit (line, "\t", -1); + if (strncmp (elements[1], NAMES_LIST_SUBJECT, + strlen (NAMES_LIST_SUBJECT)) == 0) { + unicode_version = + g_strdup (elements[1] + strlen (NAMES_LIST_SUBJECT) + 1); + has_version = TRUE; + } + g_strfreev (elements); + } + return TRUE; +} + +static gboolean +ucd_names_list_parse_alias (const gchar *line, + UnicodeData *data) +{ + g_return_val_if_fail (line != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + if (*line == '\0') + return FALSE; + data->alias = g_strdup (line); + return TRUE; +} + +static gboolean +ucd_names_list_parse_indent_line (const gchar *line, + UnicodeData *data) +{ + g_return_val_if_fail (line != NULL, FALSE); + + switch (*line) { + case '\0': + return FALSE; + case '=': + line++; + while (*line == ' ') line++; + return ucd_names_list_parse_alias (line, data); + default:; + } + return TRUE; +} + +static gboolean +ucd_names_list_parse_line (const gchar *line, + UnicodeData *data) +{ + g_return_val_if_fail (line != NULL, FALSE); + + switch (*line) { + case '\0': + return TRUE; + case ';': + return TRUE; + case '@': + return ucd_names_list_parse_comment (line); + case '\t': + return ucd_names_list_parse_indent_line (line + 1, data); + default:; + } + if (g_ascii_isxdigit (*line)) { + gchar **elements = g_strsplit (line, "\t", -1); + gunichar code; + gchar *name; + + if (g_strv_length (elements) < 2) { + g_strfreev (elements); + return FALSE; + } + code = g_ascii_strtoull (elements[0], NULL, 16); + name = g_strdup (elements[1]); + if (data->name) { + unicode_data_new_object (data); + unicode_data_reset (data); + } + data->code = code; + data->name = name; + } + return TRUE; +} + +static gboolean +ucd_blocks_parse_comment (const gchar *line) +{ + static gboolean has_version = FALSE; + + g_return_val_if_fail (line != NULL, FALSE); + + if (has_version) + return TRUE; + while (*line == ' ') line++; + if (strlen (line) > strlen (BLOCKS_SUBJECT) && + strncmp (line, BLOCKS_SUBJECT, strlen (BLOCKS_SUBJECT)) == 0) { + unicode_version = g_strdup (line + strlen (BLOCKS_SUBJECT) + 1); + has_version = TRUE; + } + return TRUE; +} + +static gboolean +ucd_blocks_parse_line (const gchar *line, + UnicodeData *data) +{ + g_return_val_if_fail (line != NULL, FALSE); + + switch (*line) { + case '\0': + return TRUE; + case '#': + return ucd_blocks_parse_comment (line + 1); + default:; + } + if (g_ascii_isxdigit (*line)) { + gchar *endptr = NULL; + gunichar start = g_ascii_strtoull (line, &endptr, 16); + gunichar end; + gchar *name = NULL; + + if (endptr == NULL || *endptr == '\0') + return FALSE; + while (*endptr == '.') endptr++; + line = endptr; + endptr = NULL; + end = g_ascii_strtoull (line, &endptr, 16); + if (endptr == NULL || *endptr == '\0') + return FALSE; + while (*endptr == ';') endptr++; + while (*endptr == ' ') endptr++; + if (*endptr == '\0') + return FALSE; + name = g_strdup (endptr); + if (data->name) { + unicode_block_new_object (data); + unicode_data_reset (data); + } + data->start = start; + data->end = end; + data->name = name; + } + return TRUE; +} + +static gboolean +ucd_parse_file (const gchar *filename, + GSList **list, + UCDType type) +{ + UnicodeData data = { 0, }; + gchar *content = NULL; + gsize length = 0; + GError *error = NULL; + gchar *head, *end, *line; + int n = 1; + + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (list != 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_ucd_names_list; + } + head = end = content; + while (*end == '\n' && end - content < length) { + end++; + n++; + } + head = end; + while (end - content < length) { + while (*end != '\n' && end - content < length) + end++; + if (end - content >= length) + break; + line = g_strndup (head, end - head); + switch (type) { + case UCD_NAMES_LIST: + if (!ucd_names_list_parse_line (line, &data)) { + g_warning ("parse error #%d in %s version %s: %s", + n, filename, + unicode_version ? unicode_version : "(null)", + line); + } + break; + case UCD_BLOCKS: + if (!ucd_blocks_parse_line (line, &data)) { + g_warning ("parse error #%d in %s version %s: %s", + n, filename, + unicode_version ? unicode_version : "(null)", + line); + } + break; + default: + g_abort (); + } + while (*end == '\n' && end - content < length) { + end++; + n++; + } + g_free (line); + head = end; + } + if (data.name != NULL) { + switch (type) { + case UCD_NAMES_LIST: + unicode_data_new_object (&data); + break; + case UCD_BLOCKS: + unicode_block_new_object (&data); + break; + default:; + } + unicode_data_reset (&data); + } + g_free (content); + *list = data.list; + return TRUE; + +failed_to_parse_ucd_names_list: + if (error) + g_error_free (error); + g_clear_pointer (&content, g_free); + *list = data.list; + return FALSE; +} + +static void +block_list_dump (IBusUnicodeBlock *block, + GString *buff) +{ + g_return_if_fail (buff != NULL); + + g_string_append (buff, " /* TRANSLATORS: You might refer the " \ + "translations from gucharmap with\n" \ + " the following command:\n" \ + " msgmerge -C gucharmap.po ibus.po " \ + "ibus.pot */\n"); + gchar *line = g_strdup_printf (" N_(\"%s\"),\n", + ibus_unicode_block_get_name (block)); + g_string_append (buff, line); +} + +static void +ucd_block_translatable_save (const gchar *filename, + GSList *blocks_list) +{ + gchar *content = NULL; + gsize length = 0; + GError *error = NULL; + gchar *p; + GString *buff = NULL; + int i; + GSList *list = blocks_list; + + g_return_if_fail (filename != NULL); + g_return_if_fail (list != NULL); + + if (!g_file_get_contents (__FILE__, &content, &length, &error)) { + g_warning ("Failed to load %s: %s", __FILE__, error->message); + g_clear_pointer (&error, g_error_free); + return; + } + + buff = g_string_new (NULL); + p = content; + for (i = 0; i < LICENSE_LINES; i++, p++) { + if ((p = strchr (p, '\n')) == NULL) + break; + } + if (p != NULL) { + g_string_append (buff, g_strndup (content, p - content)); + g_string_append_c (buff, '\n'); + } + g_clear_pointer (&content, g_free); + + g_string_append (buff, g_strdup ("\n")); + g_string_append (buff, g_strdup_printf ("/* This file is generated by %s. */", __FILE__)); + g_string_append (buff, g_strdup ("\n")); + g_string_append (buff, g_strdup ("include \n")); + g_string_append (buff, g_strdup ("\n")); + g_string_append (buff, g_strdup ("#ifndef __IBUS_UNICODE_GEN_H_\n")); + g_string_append (buff, g_strdup ("#define __IBUS_UNICODE_GEN_H_\n")); + g_string_append (buff, g_strdup ("const static char *unicode_blocks[] = {\n")); + g_slist_foreach (list, (GFunc)block_list_dump, buff); + g_string_append (buff, g_strdup ("};\n")); + g_string_append (buff, g_strdup ("#endif\n")); + + if (!g_file_set_contents (filename, buff->str, -1, &error)) { + g_warning ("Failed to save emoji category file %s: %s", filename, error->message); + g_error_free (error); + } + + g_string_free (buff, TRUE); +} + +int +main (int argc, char *argv[]) +{ + gchar *prgname; + gchar *input_names_list = NULL; + gchar *input_blocks = NULL; + gchar *output_names_list = NULL; + gchar *output_blocks = NULL; + gchar *output_blocks_trans = NULL; + GOptionEntry entries[] = { + { "input-names-list", 'n', 0, G_OPTION_ARG_STRING, &input_names_list, + "Parse NamesList.txt FILE in unicode.org ", + "FILE" + }, + { "input-blocks", 'b', 0, G_OPTION_ARG_STRING, &input_blocks, + "Parse Blocks.txt FILE in unicode.org ", + "FILE" + }, + { "output-names-list", 'o', 0, G_OPTION_ARG_STRING, &output_names_list, + "Save the Unicode data as FILE", + "FILE" + }, + { "output-blocks", 'B', 0, G_OPTION_ARG_STRING, &output_blocks, + "Save the Unicode block list as FILE", + "FILE" + }, + { "output-blocks-trans", 'C', 0, G_OPTION_ARG_STRING, + &output_blocks_trans, + "Save the translatable Unicode blocks as FILE", + "FILE" + }, + { NULL } + }; + GOptionContext *context; + GError *error = NULL; + GSList *names_list = NULL; + GSList *blocks_list = NULL; + +#ifdef HAVE_LOCALE_H + /* To output emoji warnings. */ + setlocale (LC_ALL, ""); +#endif + + 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) { + 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); + + if (input_names_list) { + ucd_parse_file (input_names_list, &names_list, UCD_NAMES_LIST); + g_free (input_names_list); + } + if (output_names_list && names_list) + ibus_unicode_data_save (output_names_list, names_list); + g_free (output_names_list); + + if (input_blocks) { + ucd_parse_file (input_blocks, &blocks_list, UCD_BLOCKS); + g_free (input_blocks); + } + if (output_blocks && blocks_list) + ibus_unicode_block_save (output_blocks, blocks_list); + if (output_blocks_trans && blocks_list) + ucd_block_translatable_save (output_blocks_trans, blocks_list); + g_free (output_blocks); + + g_free (unicode_version); + return 0; +} diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala index f3e9f15c..555ea68f 100644 --- a/ui/gtk3/emojier.vala +++ b/ui/gtk3/emojier.vala @@ -2,7 +2,7 @@ * * ibus - The Input Bus * - * Copyright (c) 2017 Takao Fujiwara + * Copyright (c) 2017-2018 Takao Fujiwara * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,7 @@ * USA */ -class IBusEmojier : Gtk.ApplicationWindow { +public class IBusEmojier : Gtk.ApplicationWindow { private class EEntry : Gtk.SearchEntry { public EEntry() { GLib.Object( @@ -99,15 +99,70 @@ class IBusEmojier : Gtk.ApplicationWindow { } } private class EWhiteLabel : Gtk.Label { + private int m_minimum_width = 0; + private int m_natural_width = 0; + private int m_minimum_height = 0; + private int m_natural_height = 0; public EWhiteLabel(string text) { GLib.Object( name : "IBusEmojierWhiteLabel" ); - if (text != "") - set_label(text); + set_label(text); + } + public override void get_preferred_width(out int minimum_width, + out int natural_width) { + if (m_minimum_height == 0 && m_natural_height == 0) { + base.get_preferred_height(out m_minimum_height, + out m_natural_height); + } + var text = get_label(); + var ch = text.get_char(); + if (text.length == 1 && ch == '\t') { + m_minimum_width = minimum_width = m_minimum_height; + m_natural_width = natural_width = m_natural_height; + return; + } + base.get_preferred_width(out minimum_width, out natural_width); + if (text.length == 1 && (ch == '\n' || ch == '\r')) { + minimum_width /= 2; + natural_width /= 2; + m_minimum_width = minimum_width; + m_natural_width = natural_width; + return; + } + if (minimum_width < m_minimum_height) + minimum_width = m_minimum_height; + if (natural_width < m_natural_height) + natural_width = m_natural_height; + m_minimum_width = minimum_width; + m_natural_width = natural_width; + } + public override void get_preferred_height(out int minimum_height, + out int natural_height) { + if (m_minimum_width == 0 && m_natural_width == 0) { + base.get_preferred_width(out m_minimum_width, + out m_natural_width); + } + var text = get_label(); + var ch = text.get_char(); + if (text.length == 1 && ch == '\v') { + m_minimum_height = minimum_height = m_minimum_width; + m_natural_height = natural_height = m_natural_width; + return; + } + base.get_preferred_height(out minimum_height, out natural_height); + if (text.length == 1 && (ch == '\n' || ch == '\r')) { + minimum_height /= 2; + natural_height /= 2; + m_minimum_height = minimum_height; + m_natural_height = natural_height; + return; + } + m_minimum_height = minimum_height; + m_natural_height = natural_height; } } - private class ESelectedLabel : Gtk.Label { + private class ESelectedLabel : EWhiteLabel { public ESelectedLabel(string text) { GLib.Object( name : "IBusEmojierSelectedLabel" @@ -116,7 +171,7 @@ class IBusEmojier : Gtk.ApplicationWindow { set_label(text); } } - private class EGoldLabel : Gtk.Label { + private class EGoldLabel : EWhiteLabel { public EGoldLabel(string text) { GLib.Object( name : "IBusEmojierGoldLabel" @@ -167,6 +222,7 @@ class IBusEmojier : Gtk.ApplicationWindow { } private class ETitleLabelBox : Gtk.HeaderBar { private Gtk.Label m_lang_label; + private Gtk.Label m_title_label; public ETitleLabelBox(string title) { GLib.Object( @@ -177,9 +233,9 @@ class IBusEmojier : Gtk.ApplicationWindow { ); var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); set_custom_title(vbox); - var label = new Gtk.Label(title); - label.get_style_context().add_class(Gtk.STYLE_CLASS_TITLE); - vbox.pack_start(label, true, false, 0); + m_title_label = new Gtk.Label(title); + m_title_label.get_style_context().add_class(Gtk.STYLE_CLASS_TITLE); + vbox.pack_start(m_title_label, true, false, 0); m_lang_label = new Gtk.Label(null); m_lang_label.get_style_context().add_class( Gtk.STYLE_CLASS_SUBTITLE); @@ -194,10 +250,19 @@ class IBusEmojier : Gtk.ApplicationWindow { menu_button.set_tooltip_text(_("Menu")); pack_end(menu_button); } + public new void set_title(string title) { + m_title_label.set_text(title); + } public void set_lang_label(string str) { m_lang_label.set_text(str); } } + private class LoadProgressObject : GLib.Object { + public LoadProgressObject() { + } + public signal void deserialize_unicode(uint done, uint total); + } + private enum TravelDirection { NONE, @@ -207,6 +272,7 @@ class IBusEmojier : Gtk.ApplicationWindow { private const uint EMOJI_GRID_PAGE = 10; private const string EMOJI_CATEGORY_FAVORITES = N_("Favorites"); private const string EMOJI_CATEGORY_OTHERS = N_("Others"); + private const string EMOJI_CATEGORY_UNICODE = N_("Open Unicode choice"); private const unichar[] EMOJI_VARIANT_LIST = { 0x1f3fb, 0x1f3fc, 0x1f3fd, 0x1f3fe, 0x1f3ff, 0x200d }; @@ -223,6 +289,8 @@ class IBusEmojier : Gtk.ApplicationWindow { private static uint m_partial_match_length; private static uint m_partial_match_condition; private static bool m_show_emoji_variant = false; + private static int m_default_window_width; + private static int m_default_window_height; private static GLib.HashTable>? m_annotation_to_emojis_dict; private static GLib.HashTable? @@ -231,6 +299,14 @@ class IBusEmojier : Gtk.ApplicationWindow { m_category_to_emojis_dict; private static GLib.HashTable>? m_emoji_to_emoji_variants_dict; + private static GLib.HashTable? + m_unicode_to_data_dict; + private static GLib.HashTable>? + m_name_to_unicodes_dict; + private static GLib.SList m_unicode_block_list; + private static bool m_show_unicode = false; + private static LoadProgressObject m_unicode_progress_object; + private static bool m_loaded_unicode = false; private ThemedRGBA m_rgba; private Gtk.Box m_vbox; @@ -246,7 +322,7 @@ class IBusEmojier : Gtk.ApplicationWindow { private string? m_result; private string? m_unicode_point = null; private bool m_candidate_panel_is_visible; - private int m_category_active_index; + private int m_category_active_index = -1; private IBus.LookupTable m_lookup_table; private Gtk.Label[] m_candidates; private bool m_enter_notify_enable = true; @@ -254,6 +330,9 @@ class IBusEmojier : Gtk.ApplicationWindow { private uint m_entry_notify_disable_id; protected static double m_mouse_x; protected static double m_mouse_y; + private Gtk.ProgressBar m_unicode_progress_bar; + private Gtk.Label m_unicode_percent_label; + private double m_unicode_percent; public signal void candidate_clicked(uint index, uint button, uint state); @@ -402,6 +481,8 @@ class IBusEmojier : Gtk.ApplicationWindow { if (m_annotation_to_emojis_dict == null) { reload_emoji_dict(); } + + get_load_progress_object(); } @@ -433,6 +514,13 @@ class IBusEmojier : Gtk.ApplicationWindow { m_emoji_to_emoji_variants_dict = new GLib.HashTable>(GLib.str_hash, GLib.str_equal); + m_unicode_to_data_dict = + new GLib.HashTable( + GLib.direct_hash, + GLib.direct_equal); + m_name_to_unicodes_dict = + new GLib.HashTable>(GLib.str_hash, + GLib.str_equal); } @@ -482,6 +570,10 @@ class IBusEmojier : Gtk.ApplicationWindow { private static string utf8_code_point(string str) { var buff = new GLib.StringBuilder(); int length = str.char_count(); + if (length == 0) { + buff.append("U+%04X".printf(0)); + return buff.str; + } for (int i = 0; i < length; i++) { unichar ch = str.get_char(0); if (i == 0) @@ -644,6 +736,72 @@ class IBusEmojier : Gtk.ApplicationWindow { } + private static void make_unicode_block_dict() { + m_unicode_block_list = IBus.UnicodeBlock.load( + Config.PKGDATADIR + "/dicts/unicode-blocks.dict"); + foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { + unowned string name = block.get_name(); + if (m_emoji_max_seq_len < name.length) + m_emoji_max_seq_len = name.length; + } + } + + + private static void make_unicode_name_dict(Object source_object) { + IBus.UnicodeData.load_async( + Config.PKGDATADIR + "/dicts/unicode-names.dict", + source_object, + null, + (IBus.UnicodeDataLoadAsyncFinish)make_unicode_name_dict_finish); + } + + private static void + make_unicode_name_dict_finish(GLib.SList unicode_list) { + if (unicode_list == null) + return; + foreach (IBus.UnicodeData data in unicode_list) { + update_unicode_to_data_dict(data); + update_name_to_unicodes_dict(data); + } + GLib.List names = + m_name_to_unicodes_dict.get_keys(); + foreach (unowned string name in names) { + if (m_emoji_max_seq_len < name.length) + m_emoji_max_seq_len = name.length; + } + m_loaded_unicode = true; + } + + + private static void update_unicode_to_data_dict(IBus.UnicodeData data) { + unichar code = data.get_code(); + m_unicode_to_data_dict.replace(code, data); + } + + + private static void update_name_to_unicodes_dict(IBus.UnicodeData data) { + unichar code = data.get_code(); + string[] names = {data.get_name().down(), data.get_alias().down()}; + foreach (unowned string name in names) { + if (name == "") + continue; + bool has_code = false; + GLib.SList hits = + m_name_to_unicodes_dict.lookup(name).copy(); + foreach (unichar hit_code in hits) { + if (hit_code == code) { + has_code = true; + break; + } + } + if (!has_code) { + hits.append(code); + m_name_to_unicodes_dict.replace(name, hits.copy()); + } + } + } + + private void set_fixed_size() { resize(20, 1); } @@ -665,6 +823,7 @@ class IBusEmojier : Gtk.ApplicationWindow { m_scrolled_window = new EScrolledWindow(); set_fixed_size(); + m_title.set_title(_("Emoji Choice")); string language = IBus.get_language_name(m_current_lang_id); m_title.set_lang_label(language); @@ -677,12 +836,12 @@ class IBusEmojier : Gtk.ApplicationWindow { Gtk.Adjustment adjustment = m_scrolled_window.get_vadjustment(); m_list_box.set_adjustment(adjustment); m_list_box.row_activated.connect((box, gtkrow) => { - m_category_active_index = 0; + m_category_active_index = -1; EBoxRow row = gtkrow as EBoxRow; show_emoji_for_category(row.text); }); - uint n = 1; + uint n = 0; if (m_favorites.length > 0) { EBoxRow row = new EBoxRow(EMOJI_CATEGORY_FAVORITES); EPaddedLabelBox widget = @@ -716,9 +875,19 @@ class IBusEmojier : Gtk.ApplicationWindow { if (n++ == m_category_active_index) m_list_box.select_row(row); } + if (m_unicode_block_list.length() > 0) { + EBoxRow row = new EBoxRow(EMOJI_CATEGORY_UNICODE); + EPaddedLabelBox widget = + new EPaddedLabelBox(_(EMOJI_CATEGORY_UNICODE), + Gtk.Align.CENTER); + row.add(widget); + m_list_box.add(row); + if (n++ == m_category_active_index) + m_list_box.select_row(row); + } m_scrolled_window.show_all(); - if (m_category_active_index == 0) + if (m_category_active_index == -1) m_list_box.unselect_all(); m_list_box.invalidate_filter(); m_list_box.set_selection_mode(Gtk.SelectionMode.SINGLE); @@ -733,6 +902,11 @@ class IBusEmojier : Gtk.ApplicationWindow { m_lookup_table.append_candidate(text); } m_backward = category; + } else if (category == EMOJI_CATEGORY_UNICODE) { + m_category_active_index = -1; + m_show_unicode = true; + show_unicode_blocks(); + return; } else { unowned GLib.SList emojis = m_category_to_emojis_dict.lookup(category); @@ -764,6 +938,126 @@ class IBusEmojier : Gtk.ApplicationWindow { } + private void show_unicode_blocks() { + m_show_unicode = true; + if (m_default_window_width == 0 && m_default_window_height == 0) + get_size(out m_default_window_width, out m_default_window_height); + remove_all_children(); + set_fixed_size(); + + m_title.set_title(_("Unicode Choice")); + EPaddedLabelBox label = + new EPaddedLabelBox(_("Bring back emoji choice"), + Gtk.Align.CENTER, + TravelDirection.BACKWARD); + Gtk.Button button = new Gtk.Button(); + button.add(label); + m_vbox.add(button); + button.show_all(); + button.button_press_event.connect((w, e) => { + m_category_active_index = -1; + m_show_unicode = false; + hide_candidate_panel(); + return true; + }); + m_scrolled_window = new EScrolledWindow(); + m_title.set_lang_label(""); + m_vbox.add(m_scrolled_window); + Gtk.Viewport viewport = new Gtk.Viewport(null, null); + m_scrolled_window.add(viewport); + + m_list_box = new EListBox(); + viewport.add(m_list_box); + Gtk.Adjustment adjustment = m_scrolled_window.get_vadjustment(); + m_list_box.set_adjustment(adjustment); + m_list_box.row_activated.connect((box, gtkrow) => { + m_category_active_index = -1; + EBoxRow row = gtkrow as EBoxRow; + show_unicode_for_block(row.text); + }); + + uint n = 0; + foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { + string name = block.get_name(); + EBoxRow row = new EBoxRow(name); + EPaddedLabelBox widget = + new EPaddedLabelBox(_(name), Gtk.Align.CENTER); + row.add(widget); + m_list_box.add(row); + if (n++ == m_category_active_index) { + m_list_box.select_row(row); + } + } + + set_size_request(-1, m_default_window_height + 100); + m_scrolled_window.set_policy(Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC); + m_scrolled_window.show_all(); + if (m_category_active_index == -1) + m_list_box.unselect_all(); + m_list_box.invalidate_filter(); + m_list_box.set_selection_mode(Gtk.SelectionMode.SINGLE); + } + + private void show_unicode_for_block(string block_name) { + if (!m_loaded_unicode) { + remove_all_children(); + set_fixed_size(); + m_unicode_progress_bar = new Gtk.ProgressBar(); + m_unicode_progress_bar.set_ellipsize(Pango.EllipsizeMode.MIDDLE); + m_unicode_progress_bar.set_halign(Gtk.Align.CENTER); + m_unicode_progress_bar.set_valign(Gtk.Align.CENTER); + m_vbox.add(m_unicode_progress_bar); + m_unicode_progress_bar.show(); + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); + hbox.set_halign(Gtk.Align.CENTER); + hbox.set_valign(Gtk.Align.CENTER); + m_vbox.add(hbox); + var label = new Gtk.Label(_("Loading a Unicode dictionary:")); + hbox.pack_start(label, false, true, 0); + m_unicode_percent_label = new Gtk.Label(""); + hbox.pack_start(m_unicode_percent_label, false, true, 0); + hbox.show_all(); + + m_unicode_progress_object.deserialize_unicode.connect((i, n) => { + m_unicode_percent = (double)i / n; + }); + GLib.Timeout.add(100, () => { + m_unicode_progress_bar.set_fraction(m_unicode_percent); + m_unicode_percent_label.set_text( + "%.0f%%\n".printf(m_unicode_percent * 100)); + m_unicode_progress_bar.show(); + m_unicode_percent_label.show(); + if (m_loaded_unicode) { + show_unicode_for_block(block_name); + } + return !m_loaded_unicode; + }); + return; + } + unichar start = 0; + unichar end = 0; + foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { + string name = block.get_name(); + if (block_name == name) { + start = block.get_start(); + end = block.get_end(); + } + } + m_lookup_table.clear(); + for (unichar ch = start; ch < end; ch++) { + unowned IBus.UnicodeData? data = + m_unicode_to_data_dict.lookup(ch); + if (data == null) + continue; + IBus.Text text = new IBus.Text.from_unichar(ch); + m_lookup_table.append_candidate(text); + } + m_backward = block_name; + show_candidate_panel(); + } + + private void show_arrow_buttons() { Gtk.Button next_button = new Gtk.Button(); next_button.clicked.connect(() => { @@ -840,6 +1134,7 @@ class IBusEmojier : Gtk.ApplicationWindow { lookup_emojis_from_annotation(string annotation) { GLib.SList? total_emojis = null; unowned GLib.SList? sub_emojis = null; + unowned GLib.SList? sub_unicodes = null; int length = annotation.length; if (m_has_partial_match && length >= m_partial_match_length) { foreach (unowned string key in @@ -877,6 +1172,22 @@ class IBusEmojier : Gtk.ApplicationWindow { foreach (unowned string emoji in sub_emojis) total_emojis.append(emoji); } + if (length >= m_partial_match_length) { + foreach (unowned string key in m_name_to_unicodes_dict.get_keys()) { + bool matched = false; + if (key.index_of(annotation) >= 0) + matched = true; + if (!matched) + continue; + sub_unicodes = m_name_to_unicodes_dict.lookup(key); + foreach (unichar code in sub_unicodes) { + string ch = code.to_string(); + if (total_emojis.find_custom(ch, GLib.strcmp) == null) { + total_emojis.append(ch); + } + } + } + } return total_emojis; } @@ -1049,58 +1360,99 @@ class IBusEmojier : Gtk.ApplicationWindow { grid.show_all(); string text = m_lookup_table.get_candidate(cursor).text; unowned IBus.EmojiData? data = m_emoji_to_data_dict.lookup(text); - if (data == null) { - // TODO: Provide a custom description and annotation for - // the favorite emojis. - EPaddedLabelBox widget = new EPaddedLabelBox( - _("Description: %s").printf(_("None")), - Gtk.Align.START); - m_vbox.add(widget); - widget.show_all(); - show_code_point_description(text); + if (data != null) { + show_emoji_description(data, text); return; - } else { - unowned string description = data.get_description(); - EPaddedLabelBox widget = new EPaddedLabelBox( - _("Description: %s").printf(description), - Gtk.Align.START); - m_vbox.add(widget); - widget.show_all(); } - unowned GLib.SList? annotations = - data.get_annotations(); - var buff = new GLib.StringBuilder(); - int i = 0; - foreach (unowned string annotation in annotations) { - if (i++ == 0) - buff.append_printf(_("Annotations: %s"), annotation); - else - buff.append_printf(" | %s", annotation); - if (buff.str.char_count() > 30) { - EPaddedLabelBox widget = - new EPaddedLabelBox(buff.str, - Gtk.Align.START); - m_vbox.add(widget); - widget.show_all(); - buff.erase(); + if (text.char_count() <= 1) { + unichar code = text.get_char(); + unowned IBus.UnicodeData? udata = + m_unicode_to_data_dict.lookup(code); + if (udata != null) { + show_unicode_description(udata, text); + return; } } - if (buff.str != "") { - EPaddedLabelBox widget = new EPaddedLabelBox(buff.str, - Gtk.Align.START); + // TODO: Provide a custom description and annotation for + // the favorite emojis. + EPaddedLabelBox widget = new EPaddedLabelBox( + _("Description: %s").printf(_("None")), + Gtk.Align.START); + m_vbox.add(widget); + widget.show_all(); + show_code_point_description(text); + } + } + + + private void show_emoji_description(IBus.EmojiData data, + string text) { + unowned string description = data.get_description(); + { + EPaddedLabelBox widget = new EPaddedLabelBox( + _("Description: %s").printf(description), + Gtk.Align.START); + m_vbox.add(widget); + widget.show_all(); + } + unowned GLib.SList? annotations = + data.get_annotations(); + var buff = new GLib.StringBuilder(); + int i = 0; + foreach (unowned string annotation in annotations) { + if (i++ == 0) + buff.append_printf(_("Annotations: %s"), annotation); + else + buff.append_printf(" | %s", annotation); + if (buff.str.char_count() > 30) { + EPaddedLabelBox widget = + new EPaddedLabelBox(buff.str, + Gtk.Align.START); m_vbox.add(widget); widget.show_all(); + buff.erase(); } - show_code_point_description(text); } + if (buff.str != "") { + EPaddedLabelBox widget = new EPaddedLabelBox(buff.str, + Gtk.Align.START); + m_vbox.add(widget); + widget.show_all(); + } + show_code_point_description(text); + } + + private void show_unicode_description(IBus.UnicodeData data, + string text) { + unowned string name = data.get_name(); + { + EPaddedLabelBox widget = new EPaddedLabelBox( + _("Name: %s").printf(name), + Gtk.Align.START); + m_vbox.add(widget); + widget.show_all(); + } + unowned string alias = data.get_alias(); + { + EPaddedLabelBox widget = new EPaddedLabelBox( + _("Alias: %s").printf(alias), + Gtk.Align.START); + m_vbox.add(widget); + widget.show_all(); + } + show_code_point_description(text); } private void hide_candidate_panel() { m_enter_notify_enable = true; m_candidate_panel_is_visible = false; - if (m_loop.is_running()) - show_category_list(); + if (m_loop.is_running()) { + if (m_show_unicode) + show_unicode_blocks(); + else + show_category_list(); + } } @@ -1165,19 +1517,41 @@ class IBusEmojier : Gtk.ApplicationWindow { } - private void category_list_cursor_move(uint keyval) { + private bool category_list_cursor_move(uint keyval) { GLib.List list = m_list_box.get_children(); - if (keyval == Gdk.Key.Down) { - m_category_active_index = - ++m_category_active_index % ((int)list.length() + 1); - } else if (keyval == Gdk.Key.Up) { + int length = (int)list.length(); + if (length == 0) + return false; + switch(keyval) { + case Gdk.Key.Down: + if (++m_category_active_index == length) + m_category_active_index = 0; + break; + case Gdk.Key.Up: if (--m_category_active_index < 0) - m_category_active_index = (int)list.length(); + m_category_active_index = length - 1; + break; + case Gdk.Key.Home: + m_category_active_index = 0; + break; + case Gdk.Key.End: + m_category_active_index = length - 1; + break; } - Gtk.Adjustment adjustment = m_list_box.get_adjustment(); - m_scrolled_window.set_hadjustment(new Gtk.Adjustment(0, 0, 0, 0, 0, 0)); - m_scrolled_window.set_vadjustment(adjustment); - show_category_list(); + var row = m_list_box.get_selected_row(); + if (row != null) + m_list_box.unselect_row(row); + if (m_category_active_index >= 0) { + row = m_list_box.get_row_at_index(m_category_active_index); + m_list_box.select_row(row); + } else { + row = m_list_box.get_row_at_index(0); + } + Gtk.Allocation alloc = { 0, 0, 0, 0 }; + row.get_allocation(out alloc); + var adjustment = m_scrolled_window.get_vadjustment(); + adjustment.clamp_page(alloc.y, alloc.y + alloc.height); + return true; } @@ -1211,7 +1585,7 @@ class IBusEmojier : Gtk.ApplicationWindow { keyval = Gdk.Key.Up; else if (keyval == Gdk.Key.Right) keyval = Gdk.Key.Down; - category_list_cursor_move(keyval); + return category_list_cursor_move(keyval); } return true; } @@ -1227,7 +1601,7 @@ class IBusEmojier : Gtk.ApplicationWindow { else if (keyval == Gdk.Key.Up) candidate_panel_cursor_up(); } else { - category_list_cursor_move(keyval); + return category_list_cursor_move(keyval); } return true; } @@ -1262,12 +1636,25 @@ class IBusEmojier : Gtk.ApplicationWindow { ? true : false); return true; } + if (!m_candidate_panel_is_visible) + return category_list_cursor_move(keyval); return false; } private bool key_press_escape() { - if (m_backward_index >= 0 && m_backward != null) { + if (m_show_unicode) { + if (m_candidate_panel_is_visible) { + m_candidate_panel_is_visible = false; + show_unicode_blocks(); + return true; + } else { + m_show_unicode = false; + m_category_active_index = -1; + hide_candidate_panel(); + return true; + } + } else if (m_backward_index >= 0 && m_backward != null) { show_emoji_for_category(m_backward); return true; } else if (m_candidate_panel_is_visible) { @@ -1287,10 +1674,13 @@ class IBusEmojier : Gtk.ApplicationWindow { if (m_candidate_panel_is_visible) { uint index = m_lookup_table.get_cursor_pos(); candidate_panel_select_index(index); - } else if (m_category_active_index > 0) { + } else if (m_category_active_index >= 0) { Gtk.ListBoxRow gtkrow = m_list_box.get_selected_row(); EBoxRow row = gtkrow as EBoxRow; - show_emoji_for_category(row.text); + if (m_show_unicode) + show_unicode_for_block(row.text); + else + show_emoji_for_category(row.text); } return true; } @@ -1380,6 +1770,7 @@ class IBusEmojier : Gtk.ApplicationWindow { m_candidate_panel_is_visible = false; m_result = null; m_enter_notify_enable = true; + m_show_unicode = false; /* Let gtk recalculate the window size. */ resize(1, 1); @@ -1399,8 +1790,9 @@ class IBusEmojier : Gtk.ApplicationWindow { * prevention logic: * https://mail.gnome.org/archives/gtk-devel-list/2017-May/msg00026.html */ - uint32 timestamp = event.get_time(); - present_with_time(timestamp); + //uint32 timestamp = event.get_time(); + //present_with_time(timestamp); + present_centralize(event); Gdk.Device pointer; #if VALA_0_34 @@ -1646,18 +2038,24 @@ class IBusEmojier : Gtk.ApplicationWindow { Gtk.Allocation allocation; get_allocation(out allocation); Gdk.Rectangle monitor_area; + Gdk.Rectangle work_area; #if VALA_0_34 Gdk.Display display = Gdk.Display.get_default(); Gdk.Monitor monitor = display.get_monitor_at_window(this.get_window()); monitor_area = monitor.get_geometry(); + work_area = monitor.get_workarea(); #else Gdk.Screen screen = Gdk.Screen.get_default(); int monitor_num = screen.get_monitor_at_window(this.get_window()); screen.get_monitor_geometry(monitor_num, out monitor_area); + work_area = screen.get_monitor_workarea(monitor_num); #endif int x = (monitor_area.x + monitor_area.width - allocation.width)/2; int y = (monitor_area.y + monitor_area.height - allocation.height)/2; + // Do not hide a bottom panel in XFCE4 + if (work_area.y < y) + y = work_area.y; move(x, y); uint32 timestamp = event.get_time(); @@ -1723,7 +2121,6 @@ class IBusEmojier : Gtk.ApplicationWindow { string? favorite = unowned_favorites[i]; // Avoid gsetting value error by manual setting GLib.return_if_fail(favorite != null); - GLib.return_if_fail(favorite != ""); m_favorites += favorite; } for(int i = 0; i < unowned_favorite_annotations.length; i++) { @@ -1733,4 +2130,19 @@ class IBusEmojier : Gtk.ApplicationWindow { } update_favorite_emoji_dict(); } + + + private static GLib.Object get_load_progress_object() { + if (m_unicode_progress_object == null) + m_unicode_progress_object = new LoadProgressObject(); + return m_unicode_progress_object as GLib.Object; + } + + + public static void load_unicode_dict() { + if (m_unicode_block_list.length() == 0) + make_unicode_block_dict(); + if (m_name_to_unicodes_dict.size() == 0) + make_unicode_name_dict(IBusEmojier.get_load_progress_object()); + } } diff --git a/ui/gtk3/emojierapp.vala b/ui/gtk3/emojierapp.vala index 6615f22b..d816352e 100644 --- a/ui/gtk3/emojierapp.vala +++ b/ui/gtk3/emojierapp.vala @@ -176,6 +176,8 @@ public class EmojiApplication : Application { m_settings_emoji.get_strv("favorites"), m_settings_emoji.get_strv("favorite-annotations")); + IBusEmojier.load_unicode_dict(); + activate_dialog(command_line); return Posix.EXIT_SUCCESS; diff --git a/ui/gtk3/ibusemojidialog.h b/ui/gtk3/ibusemojidialog.h index ed8886a8..3b420b21 100644 --- a/ui/gtk3/ibusemojidialog.h +++ b/ui/gtk3/ibusemojidialog.h @@ -1,7 +1,7 @@ /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* vim:set et sts=4: */ /* bus - The Input Bus - * Copyright (C) 2017 Takao Fujiwara + * Copyright (C) 2017-2018 Takao Fujiwara * Copyright (C) 2017 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -196,5 +196,12 @@ void ibus_emojier_set_partial_match_length */ void ibus_emojier_set_partial_match_condition (gint condition); +/** + * ibus_emojier_load_unicode_dict: + * + * Load the dictionary of #IBusUnicodeData. + */ +void ibus_emojier_load_unicode_dict (void); + G_END_DECLS #endif diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index 4f032f6f..bcb3ed75 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-2017 Takao Fujwiara + * Copyright(c) 2015-2018 Takao Fujwiara * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -871,6 +871,7 @@ class Panel : IBus.PanelService { IBusEmojier.set_annotation_lang( m_settings_emoji.get_string("lang")); m_emojier_set_emoji_lang_id = 0; + IBusEmojier.load_unicode_dict(); return false; }); } -- 2.14.3 From 4cfd5ad7c6d071cfef6c7d678cc027ea480b8fc9 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Tue, 6 Feb 2018 11:02:09 +0900 Subject: [PATCH] Fix typo in ibusunicode.c Review URL: https://codereview.appspot.com/340740043 --- src/ibusunicode.c | 5 +++-- ui/gtk3/emojier.vala | 4 ---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ibusunicode.c b/src/ibusunicode.c index 8559819d..aac9c135 100644 --- a/src/ibusunicode.c +++ b/src/ibusunicode.c @@ -412,7 +412,8 @@ ibus_unicode_data_list_deserialize (GVariant *variant, IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, G_OBJECT_TYPE (source_object)); if (!has_signal) { - const gchar type_name = g_type_name (source_object); + const gchar *type_name = + g_type_name (G_OBJECT_TYPE (source_object)); g_warning ("GObject %s does not have the signal \"%s\"", type_name ? type_name : "(null)", IBUS_UNICODE_DESERIALIZE_SIGNALL_STR); @@ -677,7 +678,7 @@ ibus_unicode_block_class_init (IBusUnicodeBlockClass *class) GObjectClass *gobject_class = G_OBJECT_CLASS (class); IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); - object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy; + object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_block_destroy; gobject_class->set_property = (GObjectSetPropertyFunc) ibus_unicode_block_set_property; gobject_class->get_property = diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala index 555ea68f..0bf34da8 100644 --- a/ui/gtk3/emojier.vala +++ b/ui/gtk3/emojier.vala @@ -1373,8 +1373,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { return; } } - // TODO: Provide a custom description and annotation for - // the favorite emojis. EPaddedLabelBox widget = new EPaddedLabelBox( _("Description: %s").printf(_("None")), Gtk.Align.START); @@ -1790,8 +1788,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { * prevention logic: * https://mail.gnome.org/archives/gtk-devel-list/2017-May/msg00026.html */ - //uint32 timestamp = event.get_time(); - //present_with_time(timestamp); present_centralize(event); Gdk.Device pointer; -- 2.14.3