ibus/ibus-HEAD.patch
2018-02-06 14:43:55 +09:00

4445 lines
169 KiB
Diff

From bfe57d20e9d39d52428e95e493d9af0bd034a82f Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
* 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2013 Red Hat, Inc.
+ * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
*
* 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 <takao.fujiwara1@gmail.com>
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 <shawn.p.huang@gmail.com>
-# Copyright (c) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-# Copyright (c) 2007-2017 Red Hat, Inc.
+# Copyright (c) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# 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 <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2016-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
* 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2013 Red Hat, Inc.
+ * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <ibusutil.h>
#include <ibusregistry.h>
#include <ibusemoji.h>
+#include <ibusunicode.h>
#ifndef IBUS_DISABLE_DEPRECATED
#include <ibuskeysyms-compat.h>
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 <takao.fujiwara1@gmail.com>
+ * 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 <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#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 <takao.fujiwara1@gmail.com>
+ * 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 <ibus.h> 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 <gio/gio.h>
+#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 <takao.fujiwara1@gmail.com>
+ * 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 <glib/gi18n.h>
+
+#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 <takao.fujiwara1@gmail.com>
+ * 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 <config.h>
+#endif
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#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 <glib/gi18n.h>\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 <takao.fujiwara1@gmail.com>
+ * Copyright (c) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
*
* 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<string, GLib.SList<string>>?
m_annotation_to_emojis_dict;
private static GLib.HashTable<string, IBus.EmojiData>?
@@ -231,6 +299,14 @@ class IBusEmojier : Gtk.ApplicationWindow {
m_category_to_emojis_dict;
private static GLib.HashTable<string, GLib.SList<string>>?
m_emoji_to_emoji_variants_dict;
+ private static GLib.HashTable<unichar, IBus.UnicodeData>?
+ m_unicode_to_data_dict;
+ private static GLib.HashTable<string, GLib.SList<unichar>>?
+ m_name_to_unicodes_dict;
+ private static GLib.SList<IBus.UnicodeBlock> 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<string, GLib.SList<string>>(GLib.str_hash,
GLib.str_equal);
+ m_unicode_to_data_dict =
+ new GLib.HashTable<unichar, IBus.UnicodeData>(
+ GLib.direct_hash,
+ GLib.direct_equal);
+ m_name_to_unicodes_dict =
+ new GLib.HashTable<string, GLib.SList<unichar>>(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<IBus.UnicodeData> 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<unowned string> 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<unichar> 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<unowned string> 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<string>? total_emojis = null;
unowned GLib.SList<string>? sub_emojis = null;
+ unowned GLib.SList<unichar>? 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<unowned string>? 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<unowned string>? 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<weak Gtk.Widget> 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 <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
* 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 <shawn.p.huang@gmail.com>
- * Copyright(c) 2015-2017 Takao Fujwiara <takao.fujiwara1@gmail.com>
+ * Copyright(c) 2015-2018 Takao Fujwiara <takao.fujiwara1@gmail.com>
*
* 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 <takao.fujiwara1@gmail.com>
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