Skip to content

Commit

Permalink
Enable to modify the iBus keyboard layout without the root permission.
Browse files Browse the repository at this point in the history
Update from the upstream. (BUILD=4220)
* Enabled to dynamically generate the entries of iBus engines.
* Enabled to modify the iBus keyboard layout without the root permission.

-----

After this change, the contents of /usr/share/ibus/component/mozc.xml is changed as follows.

Before
```
<component>
  <name>com.google.IBus.Mozc</name>
  <description>Mozc Component</description>
  <exec>/usr/lib/ibus-mozc/ibus-engine-mozc --ibus</exec>
  <version>0.0.0.0</version>
  <author>Google Inc.</author>
  <license>New BSD</license>
  <homepage>https://github.com/google/mozc</homepage>
  <textdomain>ibus-mozc</textdomain>
<engines>
<engine>
  <description>Mozc (Japanese Input Method)</description>
  <language>ja</language>
  <icon>/usr/share/ibus-mozc/product_icon.png</icon>
  <rank>80</rank>
  <icon_prop_key>InputMode</icon_prop_key>
  <symbol>&#x3042;</symbol>
  <setup>/usr/lib/mozc/mozc_tool --mode=config_dialog</setup>
  <name>mozc-jp</name>
  <longname>Mozc</longname>
  <layout>default</layout>
</engine>
</engines>
</component>
```

After
```
<component>
  <name>com.google.IBus.Mozc</name>
  <description>Mozc Component</description>
  <exec>/usr/lib/ibus-mozc/ibus-engine-mozc --ibus</exec>
  <version>0.0.0.0</version>
  <author>Google Inc.</author>
  <license>New BSD</license>
  <homepage>https://github.com/google/mozc</homepage>
  <textdomain>ibus-mozc</textdomain>
  <engines exec="/usr/lib/ibus-mozc/ibus-engine-mozc --xml" />
</component>

<!-- Settings of <engines> and <layout> are stored in ibus_config.textproto -->
<!-- under the user configuration directory, which is either of: -->
<!-- * $XDG_CONFIG_HOME/mozc/ibus_config.textproto -->
<!-- * $HOME/.config/mozc/ibus_config.textproto -->
<!-- * $HOME/.mozc/ibus_config.textproto -->
```

Then, `/usr/lib/ibus-mozc/ibus-engine-mozc --xml` returns the values of the <engine> tags.

If `ibus_config.textproto` exists under the user config directory.
(i.e. `~/.mozc/ibus_config.textproto` or `~/.config/mozc/ibus_config.textproto`)
Mozc uses the settings in the file. If `ibus_config.textproto` does not exist,
it is created with the default values.

So, the users do not need to modify `/usr/share/ibus/component/mozc.xml` directly.
This is the same mechanism with ibus-anthy.

This change will fix two issues.

* There was no way to use Kana layout for US keyboard. With this change,
  if the layout is us, Kana layout for US keyboard is used instead of JP keyboard.
* If multilingual layouts were selected, the keyboard layout for Mozc was not stable.
  For example, when US and FR keyboards were selected in addition to Mozc,
  Mozc's layout was not stable. This change enables to specify the static layout for Mozc.
  • Loading branch information
hiroyuki-komatsu committed Dec 12, 2020
1 parent ba7cbec commit 9ba59b6
Show file tree
Hide file tree
Showing 11 changed files with 462 additions and 71 deletions.
2 changes: 1 addition & 1 deletion src/data/version/mozc_version_template.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ MAJOR = 2
MINOR = 26

# Number to be increased. This value may be replaced by other tools.
BUILD = 4219
BUILD = 4220

# Represent the platform and release channel.
REVISION = 100
Expand Down
71 changes: 53 additions & 18 deletions src/unix/ibus/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ load(
"py_binary_mozc",
"select_mozc",
)
load("//tools/build_defs:stubs.bzl", "portable_proto_library")

package(default_visibility = ["//:__subpackages__"])

Expand All @@ -50,33 +51,25 @@ py_binary_mozc(
srcs = ["gen_mozc_xml.py"],
)

# This genrule uses pkg-config in gen_mozc_xml_main.
genrule(
name = "gen_mozc_xml",
outs = ["mozc.xml"],
cmd = select_mozc(
default = "touch $@", # This is stub.
linux = ("$(location :gen_mozc_xml_main) --branding=Mozc" +
" --server_dir=" + MOZC_SERVER_DIRECTORY +
" --ibus_mozc_path=" + IBUS_MOZC_PATH +
" --ibus_mozc_icon_path=" + IBUS_MOZC_ICON_PATH +
" > $@"),
),
cmd = ("$(location :gen_mozc_xml_main) --branding=Mozc" +
" --server_dir=" + MOZC_SERVER_DIRECTORY +
" --ibus_mozc_path=" + IBUS_MOZC_PATH +
" --ibus_mozc_icon_path=" + IBUS_MOZC_ICON_PATH +
" > $@"),
exec_tools = [":gen_mozc_xml_main"],
)

# This genrule uses pkg-config in gen_mozc_xml_main.
genrule(
name = "gen_main_h",
outs = ["main.h"],
cmd = select_mozc(
default = "touch $@", # This is stub.
linux = ("$(location :gen_mozc_xml_main) --branding=Mozc" +
" --output_cpp" +
" --ibus_mozc_path=" + IBUS_MOZC_PATH +
" --ibus_mozc_icon_path=" + IBUS_MOZC_ICON_PATH +
" > $@"),
),
cmd = ("$(location :gen_mozc_xml_main) --branding=Mozc" +
" --output_cpp" +
" --ibus_mozc_path=" + IBUS_MOZC_PATH +
" --ibus_mozc_icon_path=" + IBUS_MOZC_ICON_PATH +
" > $@"),
exec_tools = [":gen_mozc_xml_main"],
)

Expand Down Expand Up @@ -169,8 +162,13 @@ cc_library_mozc(
"surrounding_text_util.h",
],
),
defines = [
"ENABLE_GTK_RENDERER",
"MOZC_ENABLE_X11_SELECTION_MONITOR",
],
deps = [
":gtk_candidate_window_handler",
":ibus_config",
":ibus_property_handler",
":ibus_utils",
":x11_selection_monitor",
Expand All @@ -180,6 +178,41 @@ cc_library_mozc(
],
)

proto_library(
name = "ibus_config_proto_full",
srcs = [
"ibus_config.proto",
],
)

portable_proto_library(
name = "ibus_config_proto",
config_string = "allow_all: true",
header_outs = [
"ibus_config.pb.h",
],
proto_deps = ["ibus_config_proto_full"],
)

cc_library_mozc(
name = "ibus_config",
srcs = ["ibus_config.cc"],
hdrs = [
"ibus_config.h",
":gen_main_h",
],
copts = ["-Wno-unused-variable"],
deps = [
":ibus_config_proto",
"//base:file_stream",
"//base:file_util",
"//base:logging",
"//base:system_util",
"//base/protobuf:text_format",
"@com_google_absl//absl/strings",
],
)

cc_binary_mozc(
name = "ibus_mozc",
srcs = select_mozc(
Expand All @@ -191,9 +224,11 @@ cc_binary_mozc(
),
data = [":gen_mozc_xml"],
deps = [
":ibus_config",
":ibus_mozc_lib",
":ibus_mozc_metadata",
"//base",
"//base:flags",
"//base:init_mozc",
],
)
Expand Down
124 changes: 84 additions & 40 deletions src/unix/ibus/gen_mozc_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@

import optparse
import os
import subprocess
import sys

# Information to generate <component> part of mozc.xml. %s will be replaced with
Expand Down Expand Up @@ -68,14 +67,69 @@
#ifndef %s
#define %s
#include <cstddef>
namespace {"""

CPP_FOOTER = """} // namespace
#endif // %s"""


def OutputXmlElement(param_dict, element_name, value):
print(' <%s>%s</%s>' % (element_name, (value % param_dict), element_name))
def GetXmlElement(param_dict, element_name, value):
return ' <%s>%s</%s>' % (element_name, (value % param_dict), element_name)


def GetTextProtoElement(param_dict, element_name, value):
return ' %s : "%s"' % (element_name, (value % param_dict))


def GetEnginesXml(param_dict, engine_common, engines, setup_arg):
"""Outputs a XML data for ibus-daemon.
Args:
param_dict: A dictionary to embed options into output string.
For example, {'product_name': 'Mozc'}.
engine_common: A dictionary from a property name to a property value that
are commonly used in all engines. For example, {'language': 'ja'}.
engines: A dictionary from a property name to a list of property values of
engines. For example, {'name': ['mozc-jp', 'mozc', 'mozc-dv']}.
setup_arg: A command line to execute Mozc's configuration tool.
Returns:
output string in XML.
"""
output = ['<engines>']
for i in range(len(engines['name'])):
output.append('<engine>')
for key in engine_common:
output.append(GetXmlElement(param_dict, key, engine_common[key]))
if setup_arg:
output.append(GetXmlElement(param_dict, 'setup', ' '.join(setup_arg)))
for key in engines:
output.append(GetXmlElement(param_dict, key, engines[key][i]))
output.append('</engine>')
output.append('</engines>')
return '\n'.join(output)


def GetIbusConfigTextProto(param_dict, engines):
"""Outputs a TextProto data for iBus config.
Args:
param_dict: A dictionary to embed options into output string.
For example, {'product_name': 'Mozc'}.
engines: A dictionary from a property name to a list of property values of
engines. For example, {'name': ['mozc-jp', 'mozc', 'mozc-dv']}.
Returns:
output string in TextProto.
"""
output = []
for i in range(len(engines['name'])):
output.append('engines {')
for key in engines:
output.append(GetTextProtoElement(param_dict, key, engines[key][i]))
output.append('}')
return '\n'.join(output)


def OutputXml(param_dict, component, engine_common, engines, setup_arg):
Expand All @@ -90,63 +144,61 @@ def OutputXml(param_dict, component, engine_common, engines, setup_arg):
are commonly used in all engines. For example, {'language': 'ja'}.
engines: A dictionary from a property name to a list of property values of
engines. For example, {'name': ['mozc-jp', 'mozc', 'mozc-dv']}.
setup_arg: A command line to execute Mozc's configuration tool.
"""
del engine_common, engines, setup_arg
print('<component>')
for key in component:
OutputXmlElement(param_dict, key, component[key])
print('<engines>')
for i in range(len(engines['name'])):
print('<engine>')
for key in engine_common:
OutputXmlElement(param_dict, key, engine_common[key])
if setup_arg:
OutputXmlElement(param_dict, 'setup', ' '.join(setup_arg))
for key in engines:
OutputXmlElement(param_dict, key, engines[key][i])
print('</engine>')
print('</engines>')
print(GetXmlElement(param_dict, key, component[key]))
print(' <engines exec="%s --xml" />' % param_dict['ibus_mozc_path'])
print('</component>')

print('''
<!-- Settings of <engines> and <layout> are stored in ibus_config.textproto -->
<!-- under the user configuration directory, which is either of: -->
<!-- * $XDG_CONFIG_HOME/mozc/ibus_config.textproto -->
<!-- * $HOME/.config/mozc/ibus_config.textproto -->
<!-- * $HOME/.mozc/ibus_config.textproto -->
''')


def OutputCppVariable(param_dict, prefix, variable_name, value):
print('const char k%s%s[] = "%s";' % (prefix, variable_name.capitalize(),
(value % param_dict)))


def OutputCpp(param_dict, component, engine_common, engines):
def OutputCpp(param_dict, component, engine_common, engines, setup_arg):
"""Outputs a C++ header file for mozc/unix/ibus/main.cc.
Args:
param_dict: see OutputXml.
component: ditto.
engine_common: ditto.
engines: ditto.
setup_arg: ditto.
"""
guard_name = 'MOZC_UNIX_IBUS_MAIN_H_'
print(CPP_HEADER % (guard_name, guard_name))
for key in component:
OutputCppVariable(param_dict, 'Component', key, component[key])
for key in engine_common:
OutputCppVariable(param_dict, 'Engine', key, engine_common[key])
OutputCppVariable(param_dict, 'Engine', 'Setup', ' '.join(setup_arg))
for key in engines:
print('const char* kEngine%sArray[] = {' % key.capitalize())
for i in range(len(engines[key])):
print('"%s",' % (engines[key][i] % param_dict))
print('};')
print('const size_t kEngineArrayLen = %s;' % len(engines['name']))
print('const char kEnginesXml[] = R"#(', end='')
print(GetEnginesXml(param_dict, engine_common, engines, setup_arg))
print(')#";')
print('const char kIbusConfigTextProto[] = R"#(', end='')
print(GetIbusConfigTextProto(param_dict, engines))
print(')#";')
print(CPP_FOOTER % guard_name)


def CheckIBusVersion(options, minimum_version):
"""Tests if ibus version is equal to or greater than the given value."""
command_line = ['pkg-config', '--exists', 'ibus-1.0 >= %s' % minimum_version]
return_code = subprocess.call(command_line)
if return_code == 0:
return True
else:
return False


def main():
"""The main function."""
parser = optparse.OptionParser(usage='Usage: %prog [options]')
Expand Down Expand Up @@ -181,31 +233,23 @@ def main():
'language': 'ja',
'icon': '%(ibus_mozc_icon_path)s',
'rank': '80',
# Make sure that the property key 'InputMode' matches to the property name
# specified to |ibus_property_new| in unix/ibus/property_handler.cc
'icon_prop_key': 'InputMode',
'symbol': '&#x3042;',
}

# DO NOT change the engine name 'mozc-jp'. The names is referenced by
# unix/ibus/mozc_engine.cc.
engines_props = {
'name': ['mozc-jp'],
'longname': ['%(product_name)s'],
'layout': ['default'],
}

# IBus 1.5.11 and greater supports 'icon_prop_key'.
# See ibus/ibus@23c45b970b195008a54884a1a9d810e7f8b22c5c
if CheckIBusVersion(options, '1.5.11'):
# Make sure that the property key 'InputMode' matches to the property name
# specified to |ibus_property_new| in unix/ibus/property_handler.cc
engine_common_props['icon_prop_key'] = 'InputMode'

if CheckIBusVersion(options, '1.5.0'):
engine_common_props['symbol'] = '&#x3042;'
engines_props['layout'] = ['default']
else:
engines_props['layout'] = ['jp']

if options.output_cpp:
OutputCpp(param_dict, IBUS_COMPONENT_PROPS, engine_common_props,
engines_props)
engines_props, setup_arg)
else:
OutputXml(param_dict, IBUS_COMPONENT_PROPS, engine_common_props,
engines_props, setup_arg)
Expand Down
Loading

0 comments on commit 9ba59b6

Please sign in to comment.