diff --git a/.gitignore b/.gitignore index 352772b..0119b7f 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ ibus-1.3.6.tar.gz /ibus-1.5.20.tar.gz /ibus-1.5.21.tar.gz /ibus-1.5.22.tar.gz +/ibus-simple-1.5.22.20200821.xml.gz diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch index 1ed4aac..3b145c5 100644 --- a/ibus-HEAD.patch +++ b/ibus-HEAD.patch @@ -597,3 +597,1490 @@ index b54ef817..59787a80 100644 -- 2.24.1 +From 0da3cece88c8b94c0721aa7aca4f2d427aa22069 Mon Sep 17 00:00:00 2001 +From: Neil Shepperd +Date: Wed, 22 Jul 2020 15:31:29 +0900 +Subject: [PATCH 1/9] src: Skip parsing of compose sequence with invalid + keysyms +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Instead of continuing with the keysym defaulted to , print a +warning and skip the broken XCompose rule entirely. Fixes a bug where +an ~/.XCompose file with a error breaks the delete key. + +Tested locally with the example from launchpad bug below: + + <\> <)> : "☭" # HAMMER AND SICKLE + +This is incorrect syntax as neither <\> nor <)> are correct keysym +names. Before this patch, ibus-daemon -v prints a warning, but +pressing delete twice produces ☭ instead of its normal function. After +this patch, ibus-daemon -v prints a slightly better warning, and the +delete key is unaffected. + +BUG=https://github.com/ibus/ibus/issues/2130 +BUG=https://bugs.launchpad.net/ubuntu/+source/ibus/+bug/1849399 +--- + src/ibuscomposetable.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c +index 3f439134..c50be2b3 100644 +--- a/src/ibuscomposetable.c ++++ b/src/ibuscomposetable.c +@@ -216,8 +216,12 @@ parse_compose_sequence (IBusComposeData *compose_data, + compose_data->sequence[n] = codepoint; + } + +- if (codepoint == IBUS_KEY_VoidSymbol) +- g_warning ("Could not get code point of keysym %s", match); ++ if (codepoint == IBUS_KEY_VoidSymbol) { ++ g_warning ("Could not get code point of keysym %s: %s", ++ match, line); ++ g_free (match); ++ goto fail; ++ } + g_free (match); + n++; + } +-- +2.24.1 + +From 0ad5e9a6b6611b53c63e635e89b42e30e43ac701 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Wed, 5 Aug 2020 19:50:02 +0900 +Subject: [PATCH 2/9] setup: Delete autostart setting + +BUG=https://github.com/ibus/ibus/pull/2224 +--- + setup/main.py | 38 -------------------------------- + setup/setup.ui | 59 -------------------------------------------------- + 2 files changed, 97 deletions(-) + +diff --git a/setup/main.py b/setup/main.py +index f6adb098..d5e2078c 100644 +--- a/setup/main.py ++++ b/setup/main.py +@@ -398,13 +398,6 @@ class Setup(object): + self.__button_close = self.__builder.get_object("button_close") + self.__button_close.connect("clicked", Gtk.main_quit) + +- # auto start ibus +- self.__checkbutton_auto_start = self.__builder.get_object( +- "checkbutton_auto_start") +- self.__checkbutton_auto_start.set_active(self.__is_auto_start()) +- self.__checkbutton_auto_start.connect("toggled", +- self.__checkbutton_auto_start_toggled_cb) +- + self.__init_hotkeys() + self.__init_panel() + self.__init_general() +@@ -647,37 +640,6 @@ class Setup(object): + # set new value + model.set(iter, COLUMN_PRELOAD, data[DATA_PRELOAD]) + +- def __is_auto_start(self): +- link_file = path.join(GLib.get_user_config_dir(), +- "autostart/ibus.desktop") +- ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), +- "share/applications/ibus.desktop") +- +- if not path.exists(link_file): +- return False +- if not path.islink(link_file): +- return False +- if path.realpath(link_file) != ibus_desktop: +- return False +- return True +- +- def __checkbutton_auto_start_toggled_cb(self, button): +- auto_start_dir = path.join(GLib.get_user_config_dir(), "autostart") +- if not path.isdir(auto_start_dir): +- os.makedirs(auto_start_dir) +- +- link_file = path.join(GLib.get_user_config_dir(), +- "autostart/ibus.desktop") +- ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), +- "share/applications/ibus.desktop") +- # unlink file +- try: +- os.unlink(link_file) +- except: +- pass +- if self.__checkbutton_auto_start.get_active(): +- os.symlink(ibus_desktop, link_file) +- + def __sigusr1_cb(self, *args): + self.__window.present() + +diff --git a/setup/setup.ui b/setup/setup.ui +index 56453054..250f43a0 100644 +--- a/setup/setup.ui ++++ b/setup/setup.ui +@@ -1307,65 +1307,6 @@ + vertical + False + True +- +- +- +- +- +- True +- False +- <big><b>IBus</b></big> +-<small>The intelligent input bus</small> +-Homepage: https://github.com/ibus/ibus/wiki +- +- +- +- +- True +- center +- +- +- True +- True +- 1 +- +- +- +- +- False +- True +- 0 +- none +- +- +- Start ibus on login +- False +- True +- True +- False +- False +- True +- start +- True +- 6 +- 12 +- +- +- +- +- True +- False +- <b>Startup</b> +- True +- +- +- +- +- False +- False +- 2 +- +- + + + 4 +-- +2.24.1 + +From 3f098dc51a718f3bd427873607dcd47865523dce Mon Sep 17 00:00:00 2001 +From: Aaron Muir Hamilton +Date: Tue, 18 Aug 2020 13:45:32 +0900 +Subject: [PATCH 3/9] ui/gtk3: Tell Pango about the engine language in the + candidate panel + +This helps Pango select the correct font variants for the engine +language, which is especially important between languages based on han +characters which have wildly different forms of the same character. + +BUG=https://github.com/ibus/ibus/issues/2238 +--- + ui/gtk3/candidatearea.vala | 7 +++++++ + ui/gtk3/candidatepanel.vala | 9 +++++++++ + ui/gtk3/panel.vala | 2 ++ + 3 files changed, 18 insertions(+) + +diff --git a/ui/gtk3/candidatearea.vala b/ui/gtk3/candidatearea.vala +index b22ab5da..0ab41217 100644 +--- a/ui/gtk3/candidatearea.vala ++++ b/ui/gtk3/candidatearea.vala +@@ -32,6 +32,8 @@ class CandidateArea : Gtk.Box { + private bool m_show_cursor; + private ThemedRGBA m_rgba; + ++ private Pango.Attribute m_language_attribute; ++ + private const string LABELS[] = { + "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", + "9.", "0.", "a.", "b.", "c.", "d.", "e.", "f." +@@ -102,6 +104,10 @@ class CandidateArea : Gtk.Box { + m_labels[i].set_text(LABELS[i]); + } + ++ public void set_language(Pango.Attribute language_attribute) { ++ m_language_attribute = language_attribute.copy(); ++ } ++ + public void set_candidates(IBus.Text[] candidates, + uint focus_candidate = 0, + bool show_cursor = true) { +@@ -115,6 +121,7 @@ class CandidateArea : Gtk.Box { + bool visible = false; + if (i < candidates.length) { + Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(candidates[i]); ++ attrs.change(m_language_attribute.copy()); + if (i == focus_candidate && show_cursor) { + Pango.Attribute pango_attr = Pango.attr_foreground_new( + (uint16)(m_rgba.selected_fg.red * uint16.MAX), +diff --git a/ui/gtk3/candidatepanel.vala b/ui/gtk3/candidatepanel.vala +index 8994cdb9..57544df3 100644 +--- a/ui/gtk3/candidatepanel.vala ++++ b/ui/gtk3/candidatepanel.vala +@@ -34,6 +34,8 @@ public class CandidatePanel : Gtk.Box{ + + private Gdk.Rectangle m_cursor_location; + ++ private Pango.Attribute m_language_attribute; ++ + public signal void cursor_up(); + public signal void cursor_down(); + public signal void page_up(); +@@ -112,8 +114,14 @@ public class CandidatePanel : Gtk.Box{ + m_candidate_area.set_labels(labels); + } + ++ public void set_language(Pango.Attribute language_attribute) { ++ m_candidate_area.set_language(language_attribute); ++ m_language_attribute = language_attribute.copy(); ++ } ++ + private void set_attributes(Gtk.Label label, IBus.Text text) { + Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(text); ++ attrs.change(m_language_attribute.copy()); + + Gtk.StyleContext context = label.get_style_context(); + Gdk.RGBA color; +@@ -154,6 +162,7 @@ public class CandidatePanel : Gtk.Box{ + if (text != null) { + m_aux_label.set_text(text.get_text()); + Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(text); ++ attrs.change(m_language_attribute.copy()); + m_aux_label.set_attributes(attrs); + m_aux_label.show(); + } else { +diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala +index 680c86ed..8d9f5cc0 100644 +--- a/ui/gtk3/panel.vala ++++ b/ui/gtk3/panel.vala +@@ -822,6 +822,8 @@ class Panel : IBus.PanelService { + if (!m_use_system_keyboard_layout) + m_xkblayout.set_layout(engine); + ++ m_candidate_panel.set_language(new Pango.AttrLanguage(Pango.Language.from_string(engine.get_language()))); ++ + engine_contexts_insert(engine); + } + +-- +2.24.1 + +From 79a09f1e75357a9f1b38e80717a59c19cca1645e Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Tue, 18 Aug 2020 13:45:38 +0900 +Subject: [PATCH 4/9] setup: Add use-glyph-from-engine-lang + +The setting can revert the previous setting to choose glpyhs +with the current locale on lookup window instead of the engine's language. + +BUG=https://github.com/ibus/ibus/issues/2238 +--- + data/dconf/org.freedesktop.ibus.gschema.xml | 9 ++++ + setup/main.py | 7 +++ + setup/setup.ui | 49 +++++++++++++++++++++ + ui/gtk3/panel.vala | 26 ++++++++++- + 4 files changed, 89 insertions(+), 2 deletions(-) + +diff --git a/data/dconf/org.freedesktop.ibus.gschema.xml b/data/dconf/org.freedesktop.ibus.gschema.xml +index 7ae8f0f6..11a179a6 100644 +--- a/data/dconf/org.freedesktop.ibus.gschema.xml ++++ b/data/dconf/org.freedesktop.ibus.gschema.xml +@@ -165,6 +165,15 @@ + Custom font + Custom font name for language panel + ++ ++ true ++ Choose glyphs with input method's language on candidate window ++ Some code points have the different glyphs and Pango ++ determines the glyphs from the language attribute. ++ Pango chooses glyphs from the IBus engine's language ++ if the value is true and choose them from the desktop ++ locale if the value is false. ++ + + + +diff --git a/setup/main.py b/setup/main.py +index d5e2078c..8c8d7a47 100644 +--- a/setup/main.py ++++ b/setup/main.py +@@ -212,6 +212,13 @@ class Setup(object): + 'active', + Gio.SettingsBindFlags.DEFAULT) + ++ self.__checkbutton_glyph_from_engine_lang = self.__builder.get_object( ++ "checkbutton_use_glyph_from_engine_lang") ++ self.__settings_panel.bind('use-glyph-from-engine-lang', ++ self.__checkbutton_glyph_from_engine_lang, ++ 'active', ++ Gio.SettingsBindFlags.DEFAULT) ++ + def __init_general(self): + # embed preedit text + self.__checkbutton_embed_preedit_text = self.__builder.get_object( +diff --git a/setup/setup.ui b/setup/setup.ui +index 250f43a0..a15b9083 100644 +--- a/setup/setup.ui ++++ b/setup/setup.ui +@@ -1286,6 +1286,55 @@ + 1 + + ++ ++ ++ True ++ False ++ 0 ++ none ++ ++ ++ vertical ++ True ++ False ++ 6 ++ 6 ++ 24 ++ ++ ++ Choose glyphs with input method's language on candidate window ++ False ++ True ++ True ++ False ++ Choose glyphs with the input method's language on the candidate window for the duplicated code points ++ False ++ start ++ True ++ ++ ++ False ++ False ++ 0 ++ ++ ++ ++ ++ ++ ++ True ++ False ++ <b>Fonts</b> ++ True ++ ++ ++ ++ ++ False ++ False ++ 2 ++ ++ + + + 3 +diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala +index 8d9f5cc0..dc98e722 100644 +--- a/ui/gtk3/panel.vala ++++ b/ui/gtk3/panel.vala +@@ -47,6 +47,7 @@ class Panel : IBus.PanelService { + private string m_current_context_path = ""; + private string m_real_current_context_path = ""; + private bool m_use_global_engine = true; ++ private bool m_use_engine_lang = true; + private CandidatePanel m_candidate_panel; + private Switcher m_switcher; + private uint m_switcher_focus_set_engine_id; +@@ -197,6 +198,15 @@ class Panel : IBus.PanelService { + ref m_css_provider); + }); + ++ m_settings_panel.changed["use-glyph-from-engine-lang"].connect((key) => ++ { ++ m_use_engine_lang = m_settings_panel.get_boolean( ++ "use-glyph-from-engine-lang"); ++ var engine = m_bus.get_global_engine(); ++ if (engine != null) ++ set_language_from_engine(engine); ++ }); ++ + m_settings_panel.changed["show-icon-on-systray"].connect((key) => { + set_show_icon_on_systray(); + }); +@@ -732,6 +742,8 @@ class Panel : IBus.PanelService { + set_use_system_keyboard_layout(); + set_use_global_engine(); + set_use_xmodmap(); ++ m_use_engine_lang = m_settings_panel.get_boolean( ++ "use-glyph-from-engine-lang"); + update_engines(m_settings_general.get_strv("preload-engines"), + m_settings_general.get_strv("engines-order")); + BindingCommon.unbind_switch_shortcut( +@@ -801,6 +813,17 @@ class Panel : IBus.PanelService { + m_engine_contexts.replace(m_current_context_path, engine); + } + ++ private void set_language_from_engine(IBus.EngineDesc engine) { ++ if (m_use_engine_lang) { ++ m_candidate_panel.set_language(new Pango.AttrLanguage( ++ Pango.Language.from_string(engine.get_language()))); ++ } else { ++ m_candidate_panel.set_language(new Pango.AttrLanguage( ++ Pango.Language.from_string(null))); ++ } ++ ++ } ++ + private void set_engine(IBus.EngineDesc engine) { + if (m_property_icon_delay_time_id > 0) { + GLib.Source.remove(m_property_icon_delay_time_id); +@@ -822,8 +845,7 @@ class Panel : IBus.PanelService { + if (!m_use_system_keyboard_layout) + m_xkblayout.set_layout(engine); + +- m_candidate_panel.set_language(new Pango.AttrLanguage(Pango.Language.from_string(engine.get_language()))); +- ++ set_language_from_engine(engine); + engine_contexts_insert(engine); + } + +-- +2.24.1 + +From 508527daaf90901b6a7fa062372516640f88aa75 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Fri, 21 Aug 2020 09:07:39 +0900 +Subject: [PATCH 6/9] engine: Generate simple.xml with denylist + +simple.xml was generated by allowlist (whitelist) and it will be +done by denylist (blacklist). + +BUG=https://github.com/ibus/ibus/issues/2153 +--- + engine/Makefile.am | 20 ++- + engine/denylist.txt | 27 ++++ + engine/gensimple.py | 367 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 407 insertions(+), 7 deletions(-) + create mode 100644 engine/denylist.txt + create mode 100755 engine/gensimple.py + +diff --git a/engine/Makefile.am b/engine/Makefile.am +index 86f0e2b8..ca405496 100644 +--- a/engine/Makefile.am ++++ b/engine/Makefile.am +@@ -4,6 +4,7 @@ + # + # Copyright (c) 2010-2016, Google Inc. All rights reserved. + # Copyright (c) 2007-2016 Peng Huang ++# Copyright (c) 2013-2020 Takao Fujiwara + # + # This library is free software; you can redistribute it and/or + # modify it under the terms of the GNU Lesser General Public +@@ -78,20 +79,25 @@ component_DATA = \ + + componentdir = $(pkgdatadir)/component + +-CLEANFILES = \ ++MAINTAINERCLEANFILES = \ + simple.xml \ + $(NULL) + + EXTRA_DIST = \ ++ gensimple.py \ + iso639converter.py \ +- simple.xml.in \ ++ simple.xml \ + $(NULL) + +-simple.xml: simple.xml.in +- $(AM_V_GEN) sed \ +- -e 's|@VERSION[@]|$(VERSION)|g' \ +- -e 's|@libexecdir[@]|$(libexecdir)|g' $< > $@.tmp && \ +- mv $@.tmp $@ ++simple.xml: ++ $(srcdir)/gensimple.py \ ++ --input=$(datarootdir)/X11/xkb/rules/evdev.xml \ ++ --output=$@ \ ++ --version=$(VERSION).`date '+%Y%m%d'` \ ++ --exec-path=$(libexecdir)/ibus-engine-simple \ ++ --iso-path=$(datarootdir)/xml/iso-codes/iso_639.xml \ ++ --first-language \ ++ $(NULL) + + $(libibus): + $(MAKE) -C $(top_builddir)/src +diff --git a/engine/denylist.txt b/engine/denylist.txt +new file mode 100644 +index 00000000..e4cd0473 +--- /dev/null ++++ b/engine/denylist.txt +@@ -0,0 +1,27 @@ ++# vim:set fileencoding=utf-8 et sts=4 sw=4: ++# ++# ibus - Intelligent Input Bus for Linux / Unix OS ++# ++# Copyright © 2020 Takao Fujiwara ++# ++# 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, see . ++ ++# This file is a deny list (black list) and used by gensimple.py. ++# gensimple.py generates the engine list with evdev.xml and if an engine name ++# is matched with any entries in this file, the engine is excluded from the ++# engine list. ++# Asterisk(*) character can be used to match any engines. ++# E.g. xkb:cn:*:* excludes xkb:cn::zho and xkb:cn:mon_trad:mvf ++xkb:cn:*:* ++xkb:nec_vndr/jp:*:* +diff --git a/engine/gensimple.py b/engine/gensimple.py +new file mode 100755 +index 00000000..dc4ccf12 +--- /dev/null ++++ b/engine/gensimple.py +@@ -0,0 +1,367 @@ ++#!/usr/bin/python ++# vim:set fileencoding=utf-8 et sts=4 sw=4: ++# ++# ibus - Intelligent Input Bus for Linux / Unix OS ++# ++# Copyright © 2020 Takao Fujiwara ++# ++# 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, see . ++ ++ ++# This script generates simple.xml with /usr/share/X11/xkb/rules/evdev.xml, ++# /usr/share/xml/iso-codes/iso_639.xml and denylist.txt ++ ++ ++from xml.dom import minidom ++from xml.sax import make_parser as sax_make_parser ++from xml.sax.handler import feature_namespaces as sax_feature_namespaces ++from xml.sax.saxutils import XMLFilterBase, XMLGenerator, escape ++from xml.sax.xmlreader import AttributesImpl ++from xml.sax._exceptions import SAXParseException ++ ++import codecs ++import getopt ++import io ++import os ++import sys ++ ++VERSION='0.1' ++EVDEV_XML = '/usr/share/X11/xkb/rules/evdev.xml' ++EXEC_PATH='/usr/lib/ibus-engine-simple' ++ISO_PATH='/usr/share/xml/iso-codes/iso_639.xml' ++PY3K = sys.version_info >= (3, 0) ++ ++if PY3K: ++ from io import StringIO ++else: ++ # io.StringIO does not work with XMLGenerator ++ from cStringIO import StringIO ++ # iso_639.xml includes UTF-8 ++ reload(sys) ++ sys.setdefaultencoding('utf-8') ++ ++def usage(prgname): ++ print('''\ ++%s Version %s ++Usage: ++ %s [OPTION...] ++ ++Options: ++ -h, --help Show this message ++ -i, --input=EVDEV_XML Load EVDEV_XML file (default is: ++ %s) ++ -o, --output=FILE Output FILE (default is stdout) ++ -V, --version=VERSION Set IBus VERSION (default is %s) ++ -e, --exec-path=EXEC_PATH Set EXEC_PATH file (default is: ++ %s) ++ -I, --iso-path=ISO_PATH Load ISO_PATH file (default is: ++ %s) ++ -1, --first-language Pull first language only in language list ++''' % (prgname, VERSION, prgname, EVDEV_XML, VERSION, EXEC_PATH, ISO_PATH)) ++ ++ ++class EvdevXML(XMLFilterBase): ++ def __init__(self, parser=None, downstream=None, iso639=None, ++ denylist=None, author=None, first=False): ++ XMLFilterBase.__init__(self, parser) ++ self.__downstream = downstream ++ self.__iso639 = iso639 ++ self.__denylist = denylist ++ self.__author = author ++ self.__first = first ++ self.__is_layout = False ++ self.__is_description = False ++ self.__is_config_item = False ++ self.__is_variant = False ++ self.__is_iso639 = False ++ self.__is_name = False ++ self.__layout = '' ++ self.__description = '' ++ self.__variant = '' ++ self.__list_iso639 = [] ++ def startDocument(self): ++ if self.__downstream: ++ self.__downstream.startDocument() ++ self.__downstream.startElement('engines', AttributesImpl({})) ++ def endDocument(self): ++ if self.__downstream: ++ self.__downstream.endElement('engines') ++ self.__downstream.endDocument() ++ def startElement(self, name, attrs): ++ if name == 'layout': ++ self.__is_layout = True ++ elif name == 'description': ++ self.__is_description = True ++ elif name == 'configItem': ++ self.__is_config_item = True ++ elif name == 'languageList': ++ self.__list_iso639 = [] ++ elif name == 'iso639Id': ++ self.__is_iso639 = True ++ elif name == 'variant': ++ self.__is_variant = True ++ elif name == 'name': ++ self.__is_name = True ++ def endElement(self, name): ++ if name == 'layout': ++ self.__is_layout = False ++ self.__layout = '' ++ self.__description = '' ++ self.__variant = '' ++ self.__list_iso639 = [] ++ elif name == 'description': ++ self.__is_description = False ++ elif name == 'configItem': ++ self.save() ++ self.__is_config_item = False ++ elif name == 'iso639Id': ++ self.__is_iso639 = False ++ elif name == 'variant': ++ self.__is_variant = False ++ elif name == 'name': ++ self.__is_name = False ++ def characters(self, text): ++ if self.__is_description: ++ self.__description = text ++ elif self.__is_name: ++ if self.__is_variant and self.__is_config_item: ++ self.__variant = text ++ elif self.__is_layout and self.__is_config_item: ++ self.__layout = text ++ elif self.__is_iso639: ++ self.__list_iso639.append(text) ++ def save(self): ++ if not self.__downstream: ++ return ++ for iso in self.__list_iso639: ++ do_deny = False ++ for [xkb, layout, variant, lang] in self.__denylist: ++ if xkb == 'xkb' \ ++ and ( layout == self.__layout or layout == '*' ) \ ++ and ( variant == self.__variant or variant == '*' ) \ ++ and ( lang == iso or variant == '*' ): ++ do_deny = True ++ break ++ if do_deny: ++ continue ++ self.__downstream.startElement('engine', AttributesImpl({})) ++ self.__downstream.startElement('name', AttributesImpl({})) ++ name = 'xkb:%s:%s:%s' % ( ++ self.__layout, ++ self.__variant, ++ iso ++ ) ++ self.__downstream.characters(name) ++ self.__downstream.endElement('name') ++ self.__downstream.startElement('language', AttributesImpl({})) ++ iso639_1 = self.__iso639.code2to1(iso) ++ if iso639_1 != None: ++ iso = iso639_1 ++ self.__downstream.characters(iso) ++ self.__downstream.endElement('language') ++ self.__downstream.startElement('license', AttributesImpl({})) ++ self.__downstream.characters('GPL') ++ self.__downstream.endElement('license') ++ if self.__author != None: ++ self.__downstream.startElement('author', AttributesImpl({})) ++ self.__downstream.characters(self.__author) ++ self.__downstream.endElement('author') ++ self.__downstream.startElement('layout', AttributesImpl({})) ++ self.__downstream.characters(self.__layout) ++ self.__downstream.endElement('layout') ++ self.__downstream.startElement('longname', AttributesImpl({})) ++ self.__downstream.characters(self.__description) ++ self.__downstream.endElement('longname') ++ self.__downstream.startElement('description', AttributesImpl({})) ++ self.__downstream.characters(self.__description) ++ self.__downstream.endElement('description') ++ self.__downstream.startElement('icon', AttributesImpl({})) ++ self.__downstream.characters('ibus-keyboard') ++ self.__downstream.endElement('icon') ++ self.__downstream.startElement('rank', AttributesImpl({})) ++ if self.__variant == '': ++ self.__downstream.characters('50') ++ else: ++ self.__downstream.characters('1') ++ self.__downstream.endElement('rank') ++ self.__downstream.endElement('engine') ++ if self.__first: ++ break ++ ++ ++class GenerateEngineXML(): ++ _NAME = 'org.freedesktop.IBus.Simple' ++ _DESCRIPTION = 'A table based simple engine' ++ _AUTHOR = 'Peng Huang ' ++ _HOMEPAGE = 'https://github.com/ibus/ibus/wiki' ++ _DOMAIN = 'ibus' ++ def __init__(self, path, iso639=None, denylist='', version='', exec='', ++ first=False): ++ self.__path = path ++ self.__iso639 = iso639 ++ self.__denylist = denylist ++ self.__version = version ++ self.__exec = exec ++ self.__first = first ++ self.__result = StringIO() ++ downstream = XMLGenerator(self.__result, 'utf-8') ++ self.__load(downstream) ++ ++ def __load(self, downstream=None): ++ parser = sax_make_parser() ++ parser.setFeature(sax_feature_namespaces, 0) ++ self.__handler = EvdevXML(parser, ++ downstream, ++ self.__iso639, ++ self.__denylist, ++ self._AUTHOR, ++ self.__first) ++ parser.setContentHandler(self.__handler) ++ f = codecs.open(self.__path, 'r', encoding='utf-8') ++ try: ++ parser.parse(f) ++ except SAXParseException: ++ print('Error: Invalid file format: %s' % path) ++ finally: ++ f.close() ++ def write(self, output=None): ++ if output != None: ++ od = codecs.open(output, 'w', encoding='utf-8') ++ else: ++ if PY3K: ++ od = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') ++ else: ++ od = codecs.getwriter('utf-8')(sys.stdout) ++ contents = self.__result.getvalue() ++ index = contents.find('') ++ if index >= 0: ++ author = escape(self._AUTHOR) ++ contents = '%s%s\ ++%s%s%s\ ++%s%s%s\ ++%s%s' % ( ++ contents[:index], ++ self._NAME, self._DESCRIPTION, ++ self.__exec, self.__version, author, 'GPL', ++ self._HOMEPAGE, self._DOMAIN, contents[index:] ) ++ parsed = minidom.parseString(contents) ++ # format with indent and encoding attribute in header ++ xml = parsed.toprettyxml(indent=' ', encoding='utf-8') ++ # convert byte to str ++ od.write(str(xml, 'utf-8')) ++ #od.write(contents) ++ ++ ++class ISO639XML(XMLFilterBase): ++ def __init__(self, parser=None): ++ self.__code2to1 = {} ++ self.__codetoname = {} ++ XMLFilterBase.__init__(self, parser) ++ def startElement(self, name, attrs): ++ if name != 'iso_639_entry': ++ return ++ n = attrs.get('name') ++ iso639_1 = attrs.get('iso_639_1_code') ++ iso639_2b = attrs.get('iso_639_2B_code') ++ iso639_2t = attrs.get('iso_639_2T_code') ++ if iso639_1 != None: ++ self.__codetoname[iso639_1] = n ++ if iso639_2b != None: ++ self.__code2to1[iso639_2b] = iso639_1 ++ self.__codetoname[iso639_2b] = n ++ if iso639_2t != None and iso639_2b != iso639_2t: ++ self.__code2to1[iso639_2t] = iso639_1 ++ self.__codetoname[iso639_2t] = n ++ def code2to1(self, iso639_2): ++ try: ++ return self.__code2to1[iso639_2] ++ except KeyError: ++ return None ++ ++ ++def parse_iso639(path): ++ f = codecs.open(path, 'r', encoding='utf-8') ++ parser = sax_make_parser() ++ parser.setFeature(sax_feature_namespaces, 0) ++ handler = ISO639XML(parser) ++ parser.setContentHandler(handler) ++ try: ++ parser.parse(f) ++ except SAXParseException: ++ print('Error: Invalid file format: %s' % path) ++ finally: ++ f.close() ++ return handler ++ ++ ++def parse_denylist(denyfile): ++ denylist = [] ++ f = codecs.open(denyfile, 'r', encoding='utf-8') ++ for line in f.readlines(): ++ if line == '\n' or line[0] == '#': ++ continue ++ line = line.rstrip() ++ entry = line.split(':') ++ if len(entry) != 4: ++ print('WARNING: format error: \'%s\' against \'%s\'' \ ++ % (line, 'xkb:layout:variant:lang')) ++ continue ++ denylist.append(entry) ++ f.close() ++ return denylist ++ ++ ++if __name__ == '__main__': ++ prgname = os.path.basename(sys.argv[0]) ++ mydir = os.path.dirname(sys.argv[0]) ++ try: ++ opts, args = getopt.getopt(sys.argv[1:], ++ 'hi:o:V:e:I:1', ++ ['help', 'input=', 'output=', 'version=', ++ 'exec-path=', 'iso-path=', ++ 'first-language']) ++ except getopt.GetoptError as err: ++ print(err) ++ usage(prgname) ++ sys.exit(2) ++ if len(args) > 0: ++ usage(prgname) ++ sys.exit(2) ++ input = EVDEV_XML ++ output = None ++ version=VERSION ++ exec_path=EXEC_PATH ++ iso_path=ISO_PATH ++ first=False ++ for opt, arg in opts: ++ if opt in ('-h', '--help'): ++ usage(prgname) ++ sys.exit() ++ elif opt in ('-i', '--input'): ++ input = arg ++ elif opt in ('-o', '--output'): ++ output = arg ++ elif opt in ('-V', '--version'): ++ version = arg ++ elif opt in ('-e', '--exec-path'): ++ exec_path = arg ++ elif opt in ('-I', '--iso-path'): ++ iso_path = arg ++ elif opt in ('-1', '--first-langauge'): ++ first=True ++ ++ iso639 = parse_iso639(iso_path) ++ denylist = parse_denylist('%s/%s' % ( mydir, 'denylist.txt')) ++ xml = GenerateEngineXML(input, iso639, denylist, version, exec_path, first) ++ xml.write(output) +-- +2.24.1 + +From 6879879002af47d49d8740ca383a048d2ac8e904 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Fri, 21 Aug 2020 09:15:14 +0900 +Subject: [PATCH 8/9] src/tests: Fix runtest with simple.xml + +Now simple.xml.in is replaced with simple.xml and modify runtest +to copy simple.xml. + +BUG=https://github.com/ibus/ibus/issues/2153 +--- + src/tests/runtest | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/src/tests/runtest b/src/tests/runtest +index a6e4194b..11bcc6c2 100755 +--- a/src/tests/runtest ++++ b/src/tests/runtest +@@ -91,6 +91,19 @@ func_copy_component () { + fi + } + ++func_copy_simple_xml () { ++ file=$1 ++ base=`func_basename $file` ++ libexecdir=`func_dirname $file` ++ # top_srcdir != top_builddir in make dist ++ libexecdir=`echo "$libexecdir" | sed -e "s|$top_srcdir|$top_builddir|"` ++ if test -f $file; then ++ mkdir -p components ++ sed "s|\(\).*\(/ibus-engine-simple\)|\1$libexecdir\2|" \ ++ < $file > components/$base ++ fi ++} ++ + trap 'func_cleanup $tstdir' 1 2 3 15 + + tst=$1; shift +@@ -127,7 +140,7 @@ run_test_case() + exit -1 + fi + # func_copy_component replaces s/$top_srcdir/%top_builddir/ +- func_copy_component "../$top_srcdir/engine/simple.xml" ++ func_copy_simple_xml "../$top_srcdir/engine/simple.xml" + func_copy_component "../$top_srcdir/conf/memconf/memconf.xml" + + IBUS_COMPONENT_PATH=$PWD/components +-- +2.24.1 + +From 59b902a809ed628bb4d5bbad2b8bcb79a8a23208 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Fri, 21 Aug 2020 09:46:46 +0900 +Subject: [PATCH 9/9] src: Add file list in registry file + +Under Fedora Silverblue, st_mtime in /usr/share/ibus/component is +1 Jan 1970 even if ibus engines are installed and ibus-daemon +cannot detect new engines. +Now IBusObservedPath saves hashed file list besides st_mtime of +the compnent directory to detect the installed engines newly. + +BUG=https://github.com/ibus/ibus/issues/2132 +--- + src/ibuscomponent.c | 9 +- + src/ibusobservedpath.c | 277 ++++++++++++++++++++++++++++++++++++----- + src/ibusregistry.c | 6 +- + 3 files changed, 254 insertions(+), 38 deletions(-) + +diff --git a/src/ibuscomponent.c b/src/ibuscomponent.c +index 9837f47c..1404ada0 100644 +--- a/src/ibuscomponent.c ++++ b/src/ibuscomponent.c +@@ -2,7 +2,8 @@ + /* vim:set et sts=4: */ + /* bus - The Input Bus + * Copyright (C) 2008-2010 Peng Huang +- * Copyright (C) 2008-2019 Red Hat, Inc. ++ * Copyright (C) 2020 Takao Fujiwara ++ * Copyright (C) 2008-2020 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 +@@ -499,11 +500,7 @@ ibus_component_output (IBusComponent *component, + + for (p = component->priv->observed_paths; p != NULL; p = p->next ) { + IBusObservedPath *path = (IBusObservedPath *) p->data; +- +- g_string_append_indent (output, indent + 2); +- g_string_append_printf (output, "%s\n", +- path->mtime, +- path->path); ++ ibus_observed_path_output (path, output, indent + 2); + } + + g_string_append_indent (output, indent + 1); +diff --git a/src/ibusobservedpath.c b/src/ibusobservedpath.c +index 5b79f1fe..42192431 100644 +--- a/src/ibusobservedpath.c ++++ b/src/ibusobservedpath.c +@@ -2,7 +2,8 @@ + /* vim:set et sts=4: */ + /* ibus - The Input IBus + * Copyright (C) 2008-2015 Peng Huang +- * Copyright (C) 2008-2019 Red Hat, Inc. ++ * Copyright (C) 2020 Takao Fujiwara ++ * Copyright (C) 2008-2020 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 +@@ -30,9 +31,9 @@ enum { + }; + + +-/* IBusObservedPathPriv */ ++/* IBusObservedPathPrivate */ + struct _IBusObservedPathPrivate { +- gpointer pad; ++ guint *file_hash_list; + }; + typedef struct _IBusObservedPathPrivate IBusObservedPathPrivate; + +@@ -52,7 +53,9 @@ static gboolean ibus_observed_path_copy (IBusObservedPath *des + static gboolean ibus_observed_path_parse_xml_node (IBusObservedPath *path, + XMLNode *node); + +-G_DEFINE_TYPE (IBusObservedPath, ibus_observed_path, IBUS_TYPE_SERIALIZABLE) ++G_DEFINE_TYPE_WITH_PRIVATE (IBusObservedPath, ++ ibus_observed_path, ++ IBUS_TYPE_SERIALIZABLE) + + static void + ibus_observed_path_class_init (IBusObservedPathClass *class) +@@ -84,7 +87,9 @@ static gboolean + ibus_observed_path_serialize (IBusObservedPath *path, + GVariantBuilder *builder) + { ++ IBusObservedPathPrivate *priv = IBUS_OBSERVED_PATH_GET_PRIVATE (path); + gboolean retval; ++ guint i; + + retval = IBUS_SERIALIZABLE_CLASS (ibus_observed_path_parent_class)-> + serialize ((IBusSerializable *)path, builder); +@@ -93,6 +98,15 @@ ibus_observed_path_serialize (IBusObservedPath *path, + g_variant_builder_add (builder, "s", path->path); + g_variant_builder_add (builder, "x", path->mtime); + ++ if (!priv->file_hash_list) { ++ g_variant_builder_add (builder, "u", 0); ++ return TRUE; ++ } ++ for (i = 0; priv->file_hash_list[i]; i++); ++ g_variant_builder_add (builder, "u", i); ++ for (i = 0; priv->file_hash_list[i]; i++) ++ g_variant_builder_add (builder, "u", priv->file_hash_list[i]); ++ + return TRUE; + } + +@@ -100,7 +114,9 @@ static gint + ibus_observed_path_deserialize (IBusObservedPath *path, + GVariant *variant) + { ++ IBusObservedPathPrivate *priv = IBUS_OBSERVED_PATH_GET_PRIVATE (path); + gint retval; ++ guint i, length = 0; + + retval = IBUS_SERIALIZABLE_CLASS (ibus_observed_path_parent_class)-> + deserialize ((IBusSerializable *)path, variant); +@@ -109,6 +125,15 @@ ibus_observed_path_deserialize (IBusObservedPath *path, + ibus_g_variant_get_child_string (variant, retval++, &path->path); + g_variant_get_child (variant, retval++, "x", &path->mtime); + ++ if (g_variant_n_children (variant) < retval + 2) ++ return retval; ++ g_variant_get_child (variant, retval++, "u", &length); ++ if (!length) ++ return retval; ++ priv->file_hash_list = g_new0 (guint, length + 1); ++ for (i = 0; i < length; i++) ++ g_variant_get_child (variant, retval++, "u", &priv->file_hash_list[i]); ++ + return retval; + } + +@@ -116,14 +141,27 @@ static gboolean + ibus_observed_path_copy (IBusObservedPath *dest, + const IBusObservedPath *src) + { ++ IBusObservedPathPrivate *dest_priv = IBUS_OBSERVED_PATH_GET_PRIVATE (dest); ++ IBusObservedPathPrivate *src_priv = ++ IBUS_OBSERVED_PATH_GET_PRIVATE ((IBusObservedPath *)src); + gboolean retval; ++ guint i; + +- retval = IBUS_SERIALIZABLE_CLASS (ibus_observed_path_parent_class)->copy ((IBusSerializable *)dest, (IBusSerializable *)src); ++ retval = IBUS_SERIALIZABLE_CLASS (ibus_observed_path_parent_class)-> ++ copy ((IBusSerializable *)dest, (IBusSerializable *)src); + g_return_val_if_fail (retval, FALSE); + + dest->path = g_strdup (src->path); + dest->mtime = src->mtime; + ++ g_clear_pointer (&dest_priv->file_hash_list, g_free); ++ if (!src_priv->file_hash_list) ++ return TRUE; ++ for (i = 0; src_priv->file_hash_list[i]; i++); ++ dest_priv->file_hash_list = g_new0 (guint, i + 1); ++ for (i = 0; src_priv->file_hash_list[i]; i++) ++ dest_priv->file_hash_list[i] = src_priv->file_hash_list[i]; ++ + return TRUE; + } + +@@ -137,23 +175,48 @@ ibus_observed_path_copy (IBusObservedPath *dest, + + void + ibus_observed_path_output (IBusObservedPath *path, +- GString *output, +- gint indent) ++ GString *output, ++ gint indent) + { ++ IBusObservedPathPrivate *priv = IBUS_OBSERVED_PATH_GET_PRIVATE (path); ++ guint i; ++ + g_assert (IBUS_IS_OBSERVED_PATH (path)); + g_assert (output); + +- g_string_append_indent (output, indent); +- g_string_append_printf (output, "%s\n", +- path->mtime, +- path->path); ++ if (!priv->file_hash_list) { ++ g_string_append_indent (output, indent); ++ g_string_append_printf (output, "%s\n", ++ path->mtime, ++ path->path); ++ } else { ++ g_string_append_indent (output, indent); ++ g_string_append_printf ( ++ output, ++ "\n", ++ path->mtime, ++ path->path); ++ for (i = 0; priv->file_hash_list[i]; i++) { ++ g_string_append_indent (output, indent + 1); ++ g_string_append_printf (output, "\n", ++ priv->file_hash_list[i]); ++ } ++ g_string_append_indent (output, indent); ++ g_string_append_printf (output, "\n"); ++ } + } + + gboolean + ibus_observed_path_check_modification (IBusObservedPath *path) + { ++ IBusObservedPathPrivate *priv = IBUS_OBSERVED_PATH_GET_PRIVATE (path); + gchar *real_path = NULL; + struct stat buf; ++ gboolean retval = FALSE; ++ GDir *dir = NULL; ++ const gchar *name; ++ guint i = 0; ++ guint file_num = 0; + + g_assert (IBUS_IS_OBSERVED_PATH (path)); + +@@ -169,11 +232,71 @@ ibus_observed_path_check_modification (IBusObservedPath *path) + buf.st_mtime = 0; + } + +- g_free (real_path); + +- if (path->mtime == buf.st_mtime) +- return FALSE; +- return TRUE; ++ if (path->mtime != buf.st_mtime) { ++ retval = TRUE; ++ goto end_check_modification; ++ } ++ ++ /* If an ibus engine is installed, normal file system updates ++ * the directory mtime of "/usr/share/ibus/component" and ++ * path->mtime of the cache file and buf.st_mtime of the current directory ++ * could have the different values. ++ * ++ * But under a special file system, the buf.st_mtime is not updated ++ * even if an ibus engine is installed, likes Fedora Silverblue ++ * and ibus_observed_path_check_modification() could not detect ++ * the installed ibus engines. ++ * Now path->priv->file_hash_list reserves the hash list of the files ++ * in the observed directory and if a new ibus engine is installed, ++ * the hash of the compose file does not exists in the cache's ++ * file_hash_list and ibus-daemon regenerate the cache successfully. ++ */ ++ if (!priv->file_hash_list) { ++ /* If the cache version is old, ibus_registry_load_cache() returns ++ * FALSE and ibus_registry_check_modification() and this are not ++ * called. ++ * If the cache version is the latest, the cache file includes the ++ * filled file_hash_list for directories with ibus_observed_path_new() ++ * when the cache was generated. ++ * Then if file_hash_list is null, it's a simple file in ibus ++ * components and return here simply. ++ */ ++ goto end_check_modification; ++ } ++ dir = g_dir_open (real_path, 0, NULL); ++ g_return_val_if_fail (dir, FALSE); ++ ++ while ((name = g_dir_read_name (dir)) != NULL) { ++ guint current_hash; ++ gboolean has_file = FALSE; ++ ++ if (!g_str_has_suffix (name, ".xml")) ++ continue; ++ current_hash = g_str_hash (name); ++ for (i = 0; priv->file_hash_list[i]; i++) { ++ if (current_hash == priv->file_hash_list[i]) { ++ has_file = TRUE; ++ break; ++ } ++ } ++ if (!has_file) { ++ retval = TRUE; ++ goto end_check_modification; ++ } ++ file_num++; ++ } ++ if (!retval) { ++ for (i = 0; priv->file_hash_list[i]; i++); ++ if (file_num != i) ++ retval = TRUE; ++ } ++ ++end_check_modification: ++ if (dir) ++ g_dir_close (dir); ++ g_free (real_path); ++ return retval; + } + + static void +@@ -224,7 +347,7 @@ ibus_observed_path_traverse (IBusObservedPath *path, + paths = g_list_append (paths, sub); + paths = g_list_concat (paths, + ibus_observed_path_traverse (sub, dir_only)); +- } else if (!dir_only) { ++ } else if (sub->is_exist && !dir_only) { + paths = g_list_append (paths, sub); + } + } +@@ -233,36 +356,102 @@ ibus_observed_path_traverse (IBusObservedPath *path, + return paths; + } + ++ ++static gboolean ++ibus_observed_path_parse_file (IBusObservedPath *path, ++ XMLNode *node, ++ int *nth) ++{ ++ IBusObservedPathPrivate *priv = IBUS_OBSERVED_PATH_GET_PRIVATE (path); ++ gchar **attr; ++ ++ for (attr = node->attributes; attr[0]; attr += 2) { ++ guint hash = 0; ++ ++ if (g_strcmp0 (*attr, "hash") == 0) ++ hash = atol (attr[1]); ++ else if (g_strcmp0 (*attr, "name") == 0) ++ hash = g_str_hash (attr[1]); ++ if (hash) { ++ if (!priv->file_hash_list) { ++ *nth = 0; ++ priv->file_hash_list = g_new0 (guint, *nth + 2); ++ } else { ++ priv->file_hash_list = g_renew (guint, priv->file_hash_list, ++ *nth + 2); ++ } ++ priv->file_hash_list[*nth] = hash; ++ priv->file_hash_list[*nth + 1] = 0; ++ *nth += 1; ++ continue; ++ } ++ g_warning ("Unkonwn attribute %s", attr[0]); ++ } ++ ++ return TRUE; ++} ++ ++ + static gboolean + ibus_observed_path_parse_xml_node (IBusObservedPath *path, + XMLNode *node) + { ++ gchar **attr; ++ const gchar *full_path = node->text; ++ GList *p; ++ int i = 0; ++ + g_assert (IBUS_IS_OBSERVED_PATH (path)); + g_assert (node); + +- if (G_UNLIKELY (g_strcmp0 (node->name, "path") != 0)) { ++ if (G_UNLIKELY (g_strcmp0 (node->name, "path") != 0)) + return FALSE; ++ ++ for (attr = node->attributes; attr[0]; attr += 2) { ++ if (g_strcmp0 (*attr, "mtime") == 0) { ++ path->mtime = atol (attr[1]); ++ continue; ++ } ++ if (g_strcmp0 (*attr, "path") == 0) { ++ full_path = attr[1]; ++ continue; ++ } ++ if (g_strcmp0 (*attr, "type") == 0) { ++ if (!g_strcmp0 (attr[1], "dir")) ++ path->is_dir = TRUE; ++ else if (!g_strcmp0 (attr[1], "file")) ++ path->is_dir = FALSE; ++ else ++ g_warning ("The type attribute can be \"dir\" or \"file\"."); ++ continue; ++ } ++ g_warning ("Unkonwn attribute %s", attr[0]); + } + +- if (node->text[0] == '~' && node->text[1] != G_DIR_SEPARATOR) { +- g_warning ("Invalid path \"%s\"", node->text); ++ if (full_path[0] == '~' && full_path[1] != G_DIR_SEPARATOR) { ++ g_warning ("Invalid path \"%s\"", full_path); + return FALSE; + } + +- path->path = g_strdup (node->text); ++ path->path = g_strdup (full_path); + +- gchar **attr; +- for (attr = node->attributes; attr[0]; attr += 2) { +- if (g_strcmp0 (*attr, "mtime") == 0) { +- path->mtime = atol (attr[1]); ++ if (!path->is_dir) ++ return TRUE; ++ ++ for (i = 0, p = node->sub_nodes; p != NULL; p = p->next) { ++ XMLNode *sub_node = (XMLNode *)p->data; ++ ++ if (G_UNLIKELY (g_strcmp0 (sub_node->name, "file") != 0)) { ++ g_warning ("Unkonwn tag %s", sub_node->name); + continue; + } +- g_warning ("Unkonwn attribute %s", attr[0]); ++ ibus_observed_path_parse_file (path, sub_node, &i); + } + + return TRUE; + } + ++ + IBusObservedPath * + ibus_observed_path_new_from_xml_node (XMLNode *node, + gboolean fill_stat) +@@ -288,16 +477,46 @@ IBusObservedPath * + ibus_observed_path_new (const gchar *path, + gboolean fill_stat) + { +- g_assert (path); +- + IBusObservedPath *op; ++ IBusObservedPathPrivate *priv; ++ GList *file_list, *l; ++ guint i = 0; + ++ g_assert (path); + op = (IBusObservedPath *) g_object_new (IBUS_TYPE_OBSERVED_PATH, NULL); + op->path = g_strdup (path); + +- if (fill_stat) { +- ibus_observed_path_fill_stat (op); ++ priv = IBUS_OBSERVED_PATH_GET_PRIVATE (op); ++ l = file_list = ibus_observed_path_traverse (op, FALSE); ++ for (; l; l = l->next) { ++ IBusObservedPath *sub = l->data; ++ const gchar *file = NULL; ++ ++ g_return_val_if_fail (sub && sub->path, op); ++ ++ file = sub->path; ++ if (!g_str_has_suffix (file, ".xml")) ++ continue; ++ if (g_str_has_prefix (file, path)) { ++ file += strlen (path); ++ if (*file == '/') ++ file++; ++ /* Ignore sub directories */ ++ if (strchr (file, '/')) ++ continue; ++ } ++ if (!i) ++ priv->file_hash_list = g_new0 (guint, i + 2); ++ else ++ priv->file_hash_list = g_renew (guint, priv->file_hash_list, i + 2); ++ priv->file_hash_list[i] = g_str_hash (file); ++ priv->file_hash_list[i + 1] = 0; ++ ++i; + } ++ g_list_free_full (file_list, (GDestroyNotify)ibus_observed_path_destroy); ++ ++ if (fill_stat) ++ ibus_observed_path_fill_stat (op); + + return op; + } +diff --git a/src/ibusregistry.c b/src/ibusregistry.c +index 43990d5f..3386a5d1 100644 +--- a/src/ibusregistry.c ++++ b/src/ibusregistry.c +@@ -2,8 +2,8 @@ + /* vim:set et sts=4: */ + /* bus - The Input Bus + * Copyright (C) 2015 Peng Huang +- * Copyright (C) 2015-2019 Takao Fujiwara +- * Copyright (C) 2015-2019 Red Hat, Inc. ++ * Copyright (C) 2015-2020 Takao Fujiwara ++ * Copyright (C) 2015-2020 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 +@@ -29,7 +29,7 @@ + #include "ibusregistry.h" + + #define IBUS_CACHE_MAGIC 0x49425553 /* "IBUS" */ +-#define IBUS_CACHE_VERSION 0x00010512 ++#define IBUS_CACHE_VERSION 0x00010522 + + enum { + CHANGED, +-- +2.24.1 + diff --git a/ibus.spec b/ibus.spec index fa09803..38fe2f7 100644 --- a/ibus.spec +++ b/ibus.spec @@ -7,12 +7,6 @@ %global with_pkg_config %(pkg-config --version >/dev/null 2>&1 && echo -n "1" || echo -n "0") -%if (0%{?fedora} > 21 || 0%{?rhel} > 7) -%global with_kde5 1 -%else -%global with_kde5 0 -%endif - %global ibus_api_version 1.0 # for bytecompile in %%{_datadir}/ibus/setup @@ -32,13 +26,14 @@ Name: ibus Version: 1.5.22 -Release: 11%{?dist} +Release: 12%{?dist} Summary: Intelligent Input Bus for Linux OS License: LGPLv2+ URL: https://github.com/ibus/%name/wiki Source0: https://github.com/ibus/%name/releases/download/%{version}/%{name}-%{version}.tar.gz Source1: %{name}-xinput Source2: %{name}.conf.5 +Source3: %{name}-simple-1.5.22.20200821.xml.gz # Patch0: %%{name}-HEAD.patch Patch0: %{name}-HEAD.patch # Under testing #1349148 #1385349 #1350291 #1406699 #1432252 #1601577 @@ -71,9 +66,7 @@ BuildRequires: vala BuildRequires: iso-codes-devel BuildRequires: libnotify-devel BuildRequires: wayland-devel -%if %with_kde5 BuildRequires: qt5-qtbase-devel -%endif BuildRequires: cldr-emoji-annotation BuildRequires: unicode-emoji BuildRequires: unicode-ucd @@ -254,6 +247,10 @@ the functionality of the installed %{name} package. # cp client/gtk2/ibusimcontext.c client/gtk3/ibusimcontext.c || : # cp client/gtk2/ibusim.c client/gtk3/ibusim.c || : cp client/gtk2/ibusim.c client/gtk3/ibusim.c || : +cd engine +cp %{SOURCE3} simple.xml.gz +gunzip simple.xml.gz +cd .. # prep test @@ -285,9 +282,6 @@ autoreconf -f -i -v --enable-python-library \ %endif --enable-wayland \ -%if ! %with_kde5 - --disable-appindicator \ -%endif --enable-introspection \ --enable-install-tests \ %{nil} @@ -464,6 +458,11 @@ dconf update || : %{_datadir}/installed-tests/ibus %changelog +* Fri Aug 21 2020 Takao Fujiwara - 1.5.22-12 +- Generate simple.xml with denylist +- Tell Pango about the engine language in the candidate panel +- Add file list in registry file for Silverblue + * Tue Jul 28 2020 Adam Jackson - 1.5.22-11 - Require setxkbmap not xorg-x11-xkb-utils diff --git a/sources b/sources index 2691b3b..4629f12 100644 --- a/sources +++ b/sources @@ -1 +1,2 @@ SHA512 (ibus-1.5.22.tar.gz) = 0abe89acc6da8cea484a6b9f807c08e94869072f374f9e8f4541a426636f818f1c3cb8b9237f97245771f9e4bf19184983d8ac924177dc4824ca6e8b5304425d +SHA512 (ibus-simple-1.5.22.20200821.xml.gz) = f7532078bd409da0742538745d5d03942dd738a9bea935f75c9c0d74ad9891ff62fe7982a7c64ab957079583a12316d593f7f05534fa78a5c741eb5fb19f9da7