From dd4cc5b028c35f9bb8fa9d3bdc8f26bcdfc43d40 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Wed, 30 Sep 2020 20:35:23 +0900 Subject: [PATCH] ui/gtk3: Fix arguments in GLib.DBusSignalCallback for Vala 0.50 BUG=https://github.com/ibus/ibus/issues/2265 --- ui/gtk3/application.vala | 22 +++++++++++----------- ui/gtk3/extension.vala | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/ui/gtk3/application.vala b/ui/gtk3/application.vala index cc9ee54c..da65301b 100644 --- a/ui/gtk3/application.vala +++ b/ui/gtk3/application.vala @@ -3,7 +3,7 @@ * ibus - The Input Bus * * Copyright(c) 2011 Peng Huang - * Copyright(c) 2017 Takao Fujiwara + * Copyright(c) 2017-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 @@ -69,22 +69,22 @@ class Application { } private void bus_name_acquired_cb(DBusConnection connection, - string sender_name, - string object_path, - string interface_name, - string signal_name, - Variant parameters) { + string? sender_name, + string object_path, + string interface_name, + string signal_name, + Variant parameters) { debug("signal_name = %s", signal_name); m_panel = new Panel(m_bus); m_panel.load_settings(); } private void bus_name_lost_cb(DBusConnection connection, - string sender_name, - string object_path, - string interface_name, - string signal_name, - Variant parameters) { + string? sender_name, + string object_path, + string interface_name, + string signal_name, + Variant parameters) { // "Destroy" dbus method was called before this callback is called. // "Destroy" dbus method -> ibus_service_destroy() // -> g_dbus_connection_unregister_object() diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala index ea3cd464..a6f2e8e6 100644 --- a/ui/gtk3/extension.vala +++ b/ui/gtk3/extension.vala @@ -3,7 +3,7 @@ * ibus - The Input Bus * * Copyright(c) 2018 Peng Huang - * Copyright(c) 2018 Takao Fujiwara + * Copyright(c) 2018-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 @@ -67,22 +67,22 @@ class ExtensionGtk : Gtk.Application { private void bus_name_acquired_cb(DBusConnection connection, - string sender_name, - string object_path, - string interface_name, - string signal_name, - Variant parameters) { + string? sender_name, + string object_path, + string interface_name, + string signal_name, + Variant parameters) { debug("signal_name = %s", signal_name); m_panel = new PanelBinding(m_bus, this); m_panel.load_settings(); } private void bus_name_lost_cb(DBusConnection connection, - string sender_name, - string object_path, - string interface_name, - string signal_name, - Variant parameters) { + string? sender_name, + string object_path, + string interface_name, + string signal_name, + Variant parameters) { // "Destroy" dbus method was called before this callback is called. // "Destroy" dbus method -> ibus_service_destroy() // -> g_dbus_connection_unregister_object() -- 2.24.1 From 02338ce751a1ed5b9b892fba530ec2fe211d314e Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Fri, 20 Nov 2020 08:58:52 +0900 Subject: [PATCH] docs: Fix make dist --- docs/reference/ibus/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/ibus/Makefile.am b/docs/reference/ibus/Makefile.am index 1ece234c..0f307bbd 100644 --- a/docs/reference/ibus/Makefile.am +++ b/docs/reference/ibus/Makefile.am @@ -3,8 +3,8 @@ # ibus - The Input Bus # # Copyright (c) 2007-2015 Peng Huang -# Copyright (c) 2007-2015 Red Hat, Inc. -# Copyright (c) 2015 Takao Fujiwara +# Copyright (c) 2007-2020 Red Hat, Inc. +# Copyright (c) 2015-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 @@ -147,6 +147,6 @@ tmpl-build.stamp: trim-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DO # clean-local: # rm -rf tmpl ${DOC_MODULE) -CLEANFILES+= *.stamp +CLEANFILES+= *actions *.stamp -include $(top_srcdir)/git.mk -- 2.24.1 From aa558de80c224921753990806cf553428fbe7057 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Fri, 20 Nov 2020 09:03:32 +0900 Subject: [PATCH] src: Fix to build emoji-*.dict in CLDR 38 root.xml and sr_Cyrl.xml have included no contents since cldr-emoji-annotation-38 and make install failed because of no emoji-root.dict and emoji-sr.Cyrl.dict. Now the build creates the no content files but remove those files in the install hook. BUG=rhbz#1898065 --- src/Makefile.am | 61 ++++++++++++++++++++++------------------------ src/emoji-parser.c | 4 ++- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 99de1ab7..742ee7d7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ # ibus - The Input Bus # # Copyright (c) 2007-2015 Peng Huang -# Copyright (c) 2015-2019 Takao Fujiwara +# Copyright (c) 2015-2020 Takao Fujiwara # Copyright (c) 2007-2017 Red Hat, Inc. # # This library is free software; you can redistribute it and/or @@ -248,6 +248,7 @@ AM_CPPFLAGS += -DENABLE_EMOJI_DICT dictdir = $(pkgdatadir)/dicts LANG_FILES = $(basename $(notdir $(wildcard $(EMOJI_ANNOTATION_DIR)/*.xml))) EMOJI_DICT_FILES = $(patsubst %,dicts/emoji-%.dict,$(LANG_FILES)) +# emoji-root.dict, emoji-sr_Cyrl.dict have no contents. dict_DATA = $(EMOJI_DICT_FILES) noinst_PROGRAMS += emoji-parser @@ -265,6 +266,7 @@ dicts/emoji-%.dict: emoji-parser xml_derived_option="--xml-derived $(EMOJI_ANNOTATION_DIR)/../annotationsDerived/$*.xml"; \ plus_comment="derived"; \ fi; \ + is_skip=0; \ if test x"$*" = xen ; then \ $(builddir)/emoji-parser \ --unicode-emoji-dir $(UNICODE_EMOJI_DIR) \ @@ -279,48 +281,43 @@ dicts/emoji-%.dict: emoji-parser --xml $(EMOJI_ANNOTATION_DIR)/$*.xml \ $$xml_derived_option \ --out $@; \ + retval=$$?; \ + if test $$retval -eq 99 ; then \ + is_skip=1; \ + touch $@; \ + elif test $$retval -ne 0 ; then \ + echo "Fail to generate $@"; \ + abrt; \ + fi; \ fi; \ - echo "Generated $$plus_comment $@" + if test $$is_skip -eq 0 ; then \ + echo "Generated $$plus_comment $@"; \ + else \ + echo "Skip $$plus_comment $@"; \ + fi; ibusemojigen.h: dicts/emoji-en.dict $(NULL) -install-data-hook: $(dict_DATA) - @$(NORMAL_INSTALL) +# We put dicts/emoji-%.dict as the make target for the parallel build +# and the make target has to be genarated even if the file size is zero. +# But we don't want to install the zero size files and delete them +# in install-data-hook. +install-data-hook: $(AM_V_at)list='$(wildcard dicts/*.dict)'; \ test -n "$(dictdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(dictdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(dictdir)" || exit 1; \ - fi; \ for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -s "$$d$$p"; then continue; fi; \ + basename "$$p"; \ done | \ - while read files; do \ - if [ x$(AM_DEFAULT_VERBOSITY) = x1 ] ; then \ - echo "$(INSTALL_DATA) $$files '$(DESTDIR)$(dictdir)'"; \ - else \ - echo "Installing $$files"; \ - fi; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(dictdir)" || exit $$?; \ + while read file; do \ + if test -f "$(DESTDIR)$(dictdir)/$$file"; then \ + echo "Delete $(DESTDIR)$(dictdir)/$$file"; \ + rm "$(DESTDIR)$(dictdir)/$$file" || exit $$?; \ + fi; \ done -dict__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - cd "$$dir" && rm -f $$files; }; \ - } - -# for make dist -uninstall-hook: - @$(NORMAL_UNINSTALL) - $(AM_V_at)list='$(wildcard dicts/*.dict)'; \ - test -n "$(dictdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(dictdir)'; $(dict__uninstall_files_from_dir) - emoji_parser_SOURCES = \ emoji-parser.c \ $(NULL) diff --git a/src/emoji-parser.c b/src/emoji-parser.c index 96a779c6..b117b1b4 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-2018 Takao Fujiwara + * Copyright (C) 2016-2020 Takao Fujiwara * Copyright (C) 2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -1294,6 +1294,8 @@ main (int argc, char *argv[]) category_file_save (output_category, list); if (list) g_slist_free (list); + else + return 99; return 0; } -- 2.24.1 From b72efea42d5f72e08e2774ae03027c246d41cab7 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Fri, 20 Nov 2020 10:56:11 +0900 Subject: [PATCH] src: Update IBusInputPurpose and IBusInputHints in ibustypes.h Copy IBUS_INPUT_PURPOSE_TERMINAL, IBUS_INPUT_PURPOSE_PIN, IBUS_INPUT_PURPOSE_TERMINAL from GTK 3.24.14 --- src/ibustypes.h | 77 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/src/ibustypes.h b/src/ibustypes.h index 06370a27..798ad04d 100644 --- a/src/ibustypes.h +++ b/src/ibustypes.h @@ -2,7 +2,7 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2008-2015 Red Hat, Inc. + * 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 @@ -241,29 +241,46 @@ typedef void (* IBusFreeFunc) (gpointer object); * @IBUS_INPUT_PURPOSE_EMAIL: Edited field expects email address * @IBUS_INPUT_PURPOSE_NAME: Edited field expects the name of a person * @IBUS_INPUT_PURPOSE_PASSWORD: Like @IBUS_INPUT_PURPOSE_FREE_FORM, - * but characters are hidden + * but characters are hidden * @IBUS_INPUT_PURPOSE_PIN: Like @IBUS_INPUT_PURPOSE_DIGITS, but - * characters are hidden + * characters are hidden + * @IBUS_INPUT_PURPOSE_TERMINAL: Allow any character, in addition to control + * codes. Since 1.5.24 * * Describes primary purpose of the input context. This information * is particularly useful to implement intelligent behavior in * engines, such as automatic input-mode switch and text prediction. * + * Note that the purpose is not meant to impose a totally strict rule + * about allowed characters, and does not replace input validation. + * It is fine for an on-screen keyboard to let the user override the + * character set restriction that is expressed by the purpose. The + * application is expected to validate the entry contents, even if + * it specified a purpose. + * + * The difference between @IBUS_INPUT_PURPOSE_DIGITS and + * @IBUS_INPUT_PURPOSE_NUMBER is that the former accepts only digits + * while the latter also some punctuation (like commas or points, plus, + * minus) and ā€œeā€ or ā€œEā€ as in 3.14E+000. + * * This enumeration may be extended in the future; engines should * interpret unknown values as 'free form'. + * + * Since: 1.5.4 */ typedef enum { - IBUS_INPUT_PURPOSE_FREE_FORM, - IBUS_INPUT_PURPOSE_ALPHA, - IBUS_INPUT_PURPOSE_DIGITS, - IBUS_INPUT_PURPOSE_NUMBER, - IBUS_INPUT_PURPOSE_PHONE, - IBUS_INPUT_PURPOSE_URL, - IBUS_INPUT_PURPOSE_EMAIL, - IBUS_INPUT_PURPOSE_NAME, - IBUS_INPUT_PURPOSE_PASSWORD, - IBUS_INPUT_PURPOSE_PIN + IBUS_INPUT_PURPOSE_FREE_FORM, + IBUS_INPUT_PURPOSE_ALPHA, + IBUS_INPUT_PURPOSE_DIGITS, + IBUS_INPUT_PURPOSE_NUMBER, + IBUS_INPUT_PURPOSE_PHONE, + IBUS_INPUT_PURPOSE_URL, + IBUS_INPUT_PURPOSE_EMAIL, + IBUS_INPUT_PURPOSE_NAME, + IBUS_INPUT_PURPOSE_PASSWORD, + IBUS_INPUT_PURPOSE_PIN, + IBUS_INPUT_PURPOSE_TERMINAL } IBusInputPurpose; /** @@ -280,24 +297,36 @@ typedef enum * first word of each sentence * @IBUS_INPUT_HINT_INHIBIT_OSK: Suggest to not show an onscreen keyboard * (e.g for a calculator that already has all the keys). - * @IBUS_INPUT_HINT_VERTICAL_WRITING: The text is vertical. + * @IBUS_INPUT_HINT_VERTICAL_WRITING: The text is vertical. Since 1.5.11 + * @IBUS_INPUT_HINT_EMOJI: Suggest offering Emoji support. Since 1.5.24 + * @IBUS_INPUT_HINT_NO_EMOJI: Suggest not offering Emoji support. Since 1.5.24 * * Describes hints that might be taken into account by engines. Note * that engines may already tailor their behaviour according to the * #IBusInputPurpose of the entry. + * + * Some common sense is expected when using these flags - mixing + * @IBUS_INPUT_HINT_LOWERCASE with any of the uppercase hints makes no sense. + * + * This enumeration may be extended in the future; engines should + * ignore unknown values. + * + * Since: 1.5.4 */ typedef enum { - IBUS_INPUT_HINT_NONE = 0, - IBUS_INPUT_HINT_SPELLCHECK = 1 << 0, - IBUS_INPUT_HINT_NO_SPELLCHECK = 1 << 1, - IBUS_INPUT_HINT_WORD_COMPLETION = 1 << 2, - IBUS_INPUT_HINT_LOWERCASE = 1 << 3, - IBUS_INPUT_HINT_UPPERCASE_CHARS = 1 << 4, - IBUS_INPUT_HINT_UPPERCASE_WORDS = 1 << 5, - IBUS_INPUT_HINT_UPPERCASE_SENTENCES = 1 << 6, - IBUS_INPUT_HINT_INHIBIT_OSK = 1 << 7, - IBUS_INPUT_HINT_VERTICAL_WRITING = 1 << 8 + IBUS_INPUT_HINT_NONE = 0, + IBUS_INPUT_HINT_SPELLCHECK = 1 << 0, + IBUS_INPUT_HINT_NO_SPELLCHECK = 1 << 1, + IBUS_INPUT_HINT_WORD_COMPLETION = 1 << 2, + IBUS_INPUT_HINT_LOWERCASE = 1 << 3, + IBUS_INPUT_HINT_UPPERCASE_CHARS = 1 << 4, + IBUS_INPUT_HINT_UPPERCASE_WORDS = 1 << 5, + IBUS_INPUT_HINT_UPPERCASE_SENTENCES = 1 << 6, + IBUS_INPUT_HINT_INHIBIT_OSK = 1 << 7, + IBUS_INPUT_HINT_VERTICAL_WRITING = 1 << 8, + IBUS_INPUT_HINT_EMOJI = 1 << 9, + IBUS_INPUT_HINT_NO_EMOJI = 1 << 10 } IBusInputHints; #endif -- 2.24.1 From 5322c447c74a10ee54b482d6eff6da6d16a7c9ce Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Sat, 21 Nov 2020 07:41:23 +0900 Subject: [PATCH] ui/gtk3: Warn deprecated IBus XKB engines /w dialog simple.xml is updated by IBus release and some XKB engines could be deprecated with xkeyboard-config updates. Now a warning dialog is launched when the deprecated engines are changed to xkb:us::eng engine. BUG=https://github.com/ibus/ibus/issues/2274 --- ui/gtk3/panel.vala | 15 +++++++++++++++ 1 files changed, 33 insertions(+), 10 deletions(-) diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index 627e26ae..01f87e33 100644 --- a/ui/gtk3/panel.vala +++ b/ui/gtk3/panel.vala @@ -970,6 +970,21 @@ class Panel : IBus.PanelService { names = {"xkb:us::eng"}; m_settings_general.set_strv("preload-engines", names); engines = m_bus.get_engines_by_names(names); + var message = _("Your input method %s does not exist in IBus " + + "input methods so \"US\" layout was configured instead " + + "of your input method. Please run `ibus-setup` command, " + + "open \"Input Method\" tab, and configure your input " + + "methods again.").printf(names[0]); + var dialog = new Gtk.MessageDialog( + null, + Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.WARNING, + Gtk.ButtonsType.CLOSE, + message); + dialog.response.connect((id) => { + dialog.destroy(); + }); + dialog.show(); } if (m_engines.length == 0) { -- 2.28.0 From aec2ac75ea673d3701904735378765476cad0f21 Mon Sep 17 00:00:00 2001 From: Gunnar Hjalmarsson Date: Fri, 11 Dec 2020 16:27:36 +0900 Subject: [PATCH] ui/gtk3: Warning dialog for any deprecated IBus XKB engine This is a follow-up of commit 5322c447. That commit introduced a warning dialog in case of an empty engines list. This commit makes a differently worded warning dialog be shown in cases where the engines list is not empty but preload-engines includes at least one deprecated engine. It also fixes a variable confusion so a deprecated engine is mentioned in the first kind of warning dialog and not the US engine. BUG=https://github.com/ibus/ibus/issues/2274 --- ui/gtk3/panel.vala | 30 +++++++++++++++++++----------- 1 files changed, 43 insertions(+), 24 deletions(-) diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index 01f87e33..ab2005d7 100644 --- a/ui/gtk3/panel.vala +++ b/ui/gtk3/panel.vala @@ -966,25 +966,33 @@ class Panel : IBus.PanelService { /* Fedora internal patch could save engines not in simple.xml * likes 'xkb:cn::chi'. */ - if (engines.length == 0) { - names = {"xkb:us::eng"}; - m_settings_general.set_strv("preload-engines", names); - engines = m_bus.get_engines_by_names(names); - var message = _("Your input method %s does not exist in IBus " + - "input methods so \"US\" layout was configured instead " + - "of your input method. Please run `ibus-setup` command, " + - "open \"Input Method\" tab, and configure your input " + - "methods again.").printf(names[0]); + if (engines.length < names.length) { + string message1; + if (engines.length == 0) { + string[] fallback_names = {"xkb:us::eng"}; + m_settings_general.set_strv("preload-engines", fallback_names); + engines = m_bus.get_engines_by_names(fallback_names); + message1 = _("Your configured input method %s does not exist " + + "in IBus input methods so \"US\" layout was " + + "configured instead of your input method." + ).printf(names[0]); + } else { + message1 = _("At least one of your configured input methods " + + "does not exist in IBus input methods."); + } + var message2 = _("Please run `ibus-setup` command, open \"Input " + + "Method\" tab, and configure your input methods " + + "again."); var dialog = new Gtk.MessageDialog( null, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.CLOSE, - message); + "%s %s", message1, message2); dialog.response.connect((id) => { dialog.destroy(); }); - dialog.show(); + dialog.show_all(); } if (m_engines.length == 0) { -- 2.28.0 From 5d68b00e0464d43ba2f77697f9dcfbff78d7b438 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 31 Dec 2020 17:28:45 +0900 Subject: [PATCH] engine: Fix iso-path in gensimple.py Replace datarootdir with ISOCODES_PREFIX. --- engine/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/Makefile.am b/engine/Makefile.am index d810704b..1944c02b 100644 --- a/engine/Makefile.am +++ b/engine/Makefile.am @@ -104,7 +104,7 @@ simple.xml.in: --output=$@ \ --version=$(VERSION).`date '+%Y%m%d'` \ --exec-path=@libexecdir\@/ibus-engine-simple \ - --iso-path=$(datarootdir)/xml/iso-codes/iso_639.xml \ + --iso-path=$(ISOCODES_PREFIX)/share/xml/iso-codes/iso_639.xml \ --first-language \ $(NULL) -- 2.28.0 From 29959e1d2521781c544879b284e03812a2a11b2e Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 31 Dec 2020 20:00:02 +0900 Subject: [PATCH] engine: Fix input in gensimple.py Replace datarootdir with XKBCONFIG_BASE. --- configure.ac | 7 +++++++ engine/Makefile.am | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5753057b..9ed5cb66 100644 --- a/configure.ac +++ b/configure.ac @@ -720,6 +720,13 @@ PKG_CHECK_MODULES(ISOCODES, [ ISOCODES_PREFIX=`$PKG_CONFIG iso-codes --variable=prefix` AC_SUBST(ISOCODES_PREFIX) +PKG_CHECK_MODULES(XKBCONFIG, + [xkeyboard-config], + [XKBCONFIG_BASE=`$PKG_CONFIG xkeyboard-config --variable=xkb_base`], + [XKBCONFIG_BASE='$(datarootdir)/X11/xkb'] +) +AC_SUBST(XKBCONFIG_BASE) + AC_SUBST([GDBUS_CODEGEN], [`$PKG_CONFIG --variable gdbus_codegen gio-2.0`]) # OUTPUT files diff --git a/engine/Makefile.am b/engine/Makefile.am index 1944c02b..84bc7f6c 100644 --- a/engine/Makefile.am +++ b/engine/Makefile.am @@ -100,7 +100,7 @@ simple.xml: simple.xml.in simple.xml.in: $(srcdir)/gensimple.py \ - --input=$(datarootdir)/X11/xkb/rules/evdev.xml \ + --input=$(XKBCONFIG_BASE)/rules/evdev.xml \ --output=$@ \ --version=$(VERSION).`date '+%Y%m%d'` \ --exec-path=@libexecdir\@/ibus-engine-simple \ -- 2.28.0 From c7928b158741282e17a042f767bc5ae32c302c96 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Fri, 8 Jan 2021 18:45:55 +0900 Subject: [PATCH] Add GTK4 IM module BUG=https://github.com/ibus/ibus/issues/2291 --- client/Makefile.am | 7 +- client/gtk2/ibusimcontext.c | 352 +++++++++++++++++++++++++++++++----- client/gtk4/Makefile.am | 66 +++++++ client/gtk4/ibusim.c | 52 ++++++ client/gtk4/ibusimcontext.c | 1 + client/gtk4/ibusimcontext.h | 1 + configure.ac | 32 ++++ 7 files changed, 465 insertions(+), 46 deletions(-) create mode 100644 client/gtk4/Makefile.am create mode 100644 client/gtk4/ibusim.c create mode 120000 client/gtk4/ibusimcontext.c create mode 120000 client/gtk4/ibusimcontext.h diff --git a/client/Makefile.am b/client/Makefile.am index 546ca132..1744518c 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -3,7 +3,7 @@ # ibus - The Input Bus # # Copyright (c) 2007-2010 Peng Huang -# Copyright (c) 2007-2010 Red Hat, Inc. +# Copyright (c) 2007-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 @@ -28,6 +28,10 @@ if ENABLE_GTK3 GTK3 = gtk3 endif +if ENABLE_GTK4 +GTK4 = gtk4 +endif + if ENABLE_XIM X11 = x11 endif @@ -39,6 +43,7 @@ endif SUBDIRS = \ $(GTK2) \ $(GTK3) \ + $(GTK4) \ $(X11) \ $(WAYLAND) \ $(NULL) diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index 50290c55..a23fc2e3 100644 --- a/client/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c @@ -2,8 +2,8 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2015-2019 Takao Fujiwara - * Copyright (C) 2008-2019 Red Hat, Inc. + * Copyright (C) 2015-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 @@ -32,8 +32,12 @@ #include "ibusimcontext.h" #ifdef GDK_WINDOWING_WAYLAND +#if GTK_CHECK_VERSION (3, 98, 4) +#include +#else #include #endif +#endif #if !GTK_CHECK_VERSION (2, 91, 0) # define DEPRECATED_GDK_KEYSYMS 1 @@ -52,7 +56,11 @@ struct _IBusIMContext { /* instance members */ GtkIMContext *slave; +#if GTK_CHECK_VERSION (3, 98, 4) + GtkWidget *client_window; +#else GdkWindow *client_window; +#endif IBusInputContext *ibuscontext; @@ -73,7 +81,12 @@ struct _IBusIMContext { GCancellable *cancellable; GQueue *events_queue; -#if !GTK_CHECK_VERSION (3, 93, 0) +#if GTK_CHECK_VERSION (3, 98, 4) + GdkSurface *surface; + GdkDevice *device; + double x; + double y; +#else gboolean use_button_press_event; #endif }; @@ -90,9 +103,11 @@ static guint _signal_preedit_end_id = 0; static guint _signal_delete_surrounding_id = 0; static guint _signal_retrieve_surrounding_id = 0; +#if !GTK_CHECK_VERSION (3, 98, 4) static const gchar *_no_snooper_apps = NO_SNOOPER_APPS; static gboolean _use_key_snooper = ENABLE_SNOOPER; static guint _key_snooper_id = 0; +#endif static gboolean _use_sync_mode = FALSE; @@ -101,8 +116,10 @@ static gboolean _use_discard_password = FALSE; static GtkIMContext *_focus_im_context = NULL; static IBusInputContext *_fake_context = NULL; +#if !GTK_CHECK_VERSION (3, 98, 4) static GdkWindow *_input_window = NULL; static GtkWidget *_input_widget = NULL; +#endif /* functions prototype */ static void ibus_im_context_class_init (IBusIMContextClass *class); @@ -114,7 +131,11 @@ static void ibus_im_context_finalize (GObject *obj); static void ibus_im_context_reset (GtkIMContext *context); static gboolean ibus_im_context_filter_keypress (GtkIMContext *context, +#if GTK_CHECK_VERSION (3, 98, 4) + GdkEvent *key); +#else GdkEventKey *key); +#endif static void ibus_im_context_focus_in (GtkIMContext *context); static void ibus_im_context_focus_out (GtkIMContext *context); static void ibus_im_context_get_preedit_string @@ -122,9 +143,15 @@ static void ibus_im_context_get_preedit_string gchar **str, PangoAttrList **attrs, gint *cursor_pos); +#if GTK_CHECK_VERSION (3, 98, 4) +static void ibus_im_context_set_client_widget + (GtkIMContext *context, + GtkWidget *client); +#else static void ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client); +#endif static void ibus_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area); @@ -239,6 +266,7 @@ ibus_im_context_new (void) return IBUS_IM_CONTEXT (obj); } +#if !GTK_CHECK_VERSION (3, 98, 4) static gboolean _focus_in_cb (GtkWidget *widget, GdkEventFocus *event, @@ -260,22 +288,41 @@ _focus_out_cb (GtkWidget *widget, } return FALSE; } +#endif /* end of GTK_CHECK_VERSION (3, 98, 4) */ static gboolean ibus_im_context_commit_event (IBusIMContext *ibusimcontext, +#if GTK_CHECK_VERSION (3, 98, 4) + GdkEvent *event) +#else GdkEventKey *event) +#endif { + guint keyval = 0; + GdkModifierType state = 0; int i; GdkModifierType no_text_input_mask; gunichar ch; +#if GTK_CHECK_VERSION (3, 98, 4) + if (gdk_event_get_event_type (event) == GDK_KEY_RELEASE) + return FALSE; + keyval = gdk_key_event_get_keyval (event); + state = gdk_event_get_modifier_state (event); +#else if (event->type == GDK_KEY_RELEASE) return FALSE; + keyval = event->keyval; + state = event->state; +#endif + /* Ignore modifier key presses */ for (i = 0; i < G_N_ELEMENTS (IBUS_COMPOSE_IGNORE_KEYLIST); i++) - if (event->keyval == IBUS_COMPOSE_IGNORE_KEYLIST[i]) + if (keyval == IBUS_COMPOSE_IGNORE_KEYLIST[i]) return FALSE; -#if GTK_CHECK_VERSION (3, 4, 0) +#if GTK_CHECK_VERSION (3, 98, 4) + no_text_input_mask = GDK_MODIFIER_MASK; +#elif GTK_CHECK_VERSION (3, 4, 0) no_text_input_mask = gdk_keymap_get_modifier_mask ( gdk_keymap_get_for_display (gdk_display_get_default ()), GDK_MODIFIER_INTENT_NO_TEXT_INPUT); @@ -290,13 +337,13 @@ ibus_im_context_commit_event (IBusIMContext *ibusimcontext, # undef _IBUS_NO_TEXT_INPUT_MOD_MASK #endif - if (event->state & no_text_input_mask || - event->keyval == GDK_KEY_Return || - event->keyval == GDK_KEY_ISO_Enter || - event->keyval == GDK_KEY_KP_Enter) { + if (state & no_text_input_mask || + keyval == GDK_KEY_Return || + keyval == GDK_KEY_ISO_Enter || + keyval == GDK_KEY_KP_Enter) { return FALSE; } - ch = ibus_keyval_to_unicode (event->keyval); + ch = ibus_keyval_to_unicode (keyval); if (ch != 0 && !g_unichar_iscntrl (ch)) { IBusText *text = ibus_text_new_from_unichar (ch); g_signal_emit (ibusimcontext, _signal_commit_id, 0, text->text); @@ -307,14 +354,26 @@ ibus_im_context_commit_event (IBusIMContext *ibusimcontext, return FALSE; } +struct _ProcessKeyEventData { + GdkEvent *event; + IBusIMContext *ibusimcontext; +}; + +typedef struct _ProcessKeyEventData ProcessKeyEventData; + static void _process_key_event_done (GObject *object, GAsyncResult *res, gpointer user_data) { IBusInputContext *context = (IBusInputContext *)object; - GdkEventKey *event = (GdkEventKey *) user_data; + + ProcessKeyEventData *data = (ProcessKeyEventData *)user_data; + GdkEvent *event = data->event; + IBusIMContext *ibusimcontext = data->ibusimcontext; GError *error = NULL; + + g_slice_free (ProcessKeyEventData, data); gboolean retval = ibus_input_context_process_key_event_async_finish ( context, res, @@ -326,46 +385,96 @@ _process_key_event_done (GObject *object, } if (retval == FALSE) { - event->state |= IBUS_IGNORED_MASK; - gdk_event_put ((GdkEvent *)event); +#if GTK_CHECK_VERSION (3, 98, 4) + g_return_if_fail (GTK_IS_IM_CONTEXT (ibusimcontext)); + gtk_im_context_filter_key ( + GTK_IM_CONTEXT (ibusimcontext), + gdk_event_get_event_type (event) == GDK_KEY_PRESS, + gdk_event_get_surface (event), + gdk_event_get_device (event), + gdk_event_get_time (event), + gdk_key_event_get_keycode (event), + gdk_event_get_modifier_state (event) | IBUS_IGNORED_MASK, + 0); +#else + ((GdkEventKey *)event)->state |= IBUS_IGNORED_MASK; + gdk_event_put (event); +#endif } - gdk_event_free ((GdkEvent *)event); +#if GTK_CHECK_VERSION (3, 98, 4) + gdk_event_unref (event); +#else + gdk_event_free (event); +#endif } static gboolean _process_key_event (IBusInputContext *context, - GdkEventKey *event) +#if GTK_CHECK_VERSION (3, 98, 4) + GdkEvent *event, +#else + GdkEventKey *event, +#endif + IBusIMContext *ibusimcontext) { - guint state = event->state; + guint state; + guint keyval = 0; + guint16 hardware_keycode = 0; + guint keycode = 0; gboolean retval = FALSE; - if (event->type == GDK_KEY_RELEASE) { +#if GTK_CHECK_VERSION (3, 98, 4) + GdkModifierType gdkstate = gdk_event_get_modifier_state (event); + state = (uint)gdkstate; + if (gdk_event_get_event_type (event) == GDK_KEY_RELEASE) state |= IBUS_RELEASE_MASK; - } + keyval = gdk_key_event_get_keyval (event); + hardware_keycode = gdk_key_event_get_keycode (event); +#else + state = event->state; + if (event->type == GDK_KEY_RELEASE) + state |= IBUS_RELEASE_MASK; + keyval = event->keyval; + hardware_keycode = event->hardware_keycode; +#endif + keycode = hardware_keycode; if (_use_sync_mode) { retval = ibus_input_context_process_key_event (context, - event->keyval, - event->hardware_keycode - 8, + keyval, + keycode - 8, state); } else { + ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData); +#if GTK_CHECK_VERSION (3, 98, 4) + data->event = gdk_event_ref (event); +#else + data->event = gdk_event_copy ((GdkEvent *)event); +#endif + data->ibusimcontext = ibusimcontext; ibus_input_context_process_key_event_async (context, - event->keyval, - event->hardware_keycode - 8, + keyval, + keycode - 8, state, -1, NULL, _process_key_event_done, - gdk_event_copy ((GdkEvent *) event)); + data); retval = TRUE; } + /* GTK4 does not provide gtk_key_snooper_install() and also + * GtkIMContextClass->filter_keypress() cannot send the updated + * GdkEventKey so event->state is not updated here in GTK4. + */ +#if !GTK_CHECK_VERSION (3, 98, 4) if (retval) event->state |= IBUS_HANDLED_MASK; else event->state |= IBUS_IGNORED_MASK; +#endif return retval; } @@ -425,6 +534,7 @@ _set_content_type (IBusIMContext *context) } +#if !GTK_CHECK_VERSION (3, 98, 4) static gint _key_snooper_cb (GtkWidget *widget, GdkEventKey *event, @@ -526,7 +636,7 @@ _key_snooper_cb (GtkWidget *widget, ibusimcontext->time = event->time; } - retval = _process_key_event (ibuscontext, event); + retval = _process_key_event (ibuscontext, event, ibusimcontext); if (ibusimcontext != NULL) { /* unref ibusimcontext could call ibus_im_context_finalize here @@ -537,6 +647,7 @@ _key_snooper_cb (GtkWidget *widget, return retval; } +#endif static gboolean _get_boolean_env(const gchar *name, @@ -599,7 +710,11 @@ ibus_im_context_class_init (IBusIMContextClass *class) im_context_class->focus_out = ibus_im_context_focus_out; im_context_class->filter_keypress = ibus_im_context_filter_keypress; im_context_class->get_preedit_string = ibus_im_context_get_preedit_string; +#if GTK_CHECK_VERSION (3, 98, 4) + im_context_class->set_client_widget = ibus_im_context_set_client_widget; +#else im_context_class->set_client_window = ibus_im_context_set_client_window; +#endif im_context_class->set_cursor_location = ibus_im_context_set_cursor_location; im_context_class->set_use_preedit = ibus_im_context_set_use_preedit; im_context_class->set_surrounding = ibus_im_context_set_surrounding; @@ -630,8 +745,10 @@ ibus_im_context_class_init (IBusIMContextClass *class) g_signal_lookup ("retrieve-surrounding", G_TYPE_FROM_CLASS (class)); g_assert (_signal_retrieve_surrounding_id != 0); +#if !GTK_CHECK_VERSION (3, 98, 4) _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER", !(ENABLE_SNOOPER)); +#endif _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE); _use_discard_password = _get_boolean_env ("IBUS_DISCARD_PASSWORD", FALSE); @@ -656,6 +773,7 @@ ibus_im_context_class_init (IBusIMContextClass *class) g_strfreev (apps); \ } +#if !GTK_CHECK_VERSION (3, 98, 4) /* env IBUS_DISABLE_SNOOPER does not exist */ if (_use_key_snooper) { /* disable snooper if app is in _no_snooper_apps */ @@ -664,6 +782,7 @@ ibus_im_context_class_init (IBusIMContextClass *class) _no_snooper_apps, FALSE); } +#endif if (!_use_discard_password) { CHECK_APP_IN_CSV_ENV_VARIABLES (_use_discard_password, IBUS_DISCARD_PASSWORD_APPS, @@ -686,6 +805,7 @@ ibus_im_context_class_init (IBusIMContextClass *class) } +#if !GTK_CHECK_VERSION (3, 98, 4) /* always install snooper */ if (_key_snooper_id == 0) { #pragma GCC diagnostic push @@ -693,6 +813,7 @@ ibus_im_context_class_init (IBusIMContextClass *class) _key_snooper_id = gtk_key_snooper_install (_key_snooper_cb, NULL); #pragma GCC diagnostic pop } +#endif _daemon_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, ibus_bus_get_service_name (_bus), @@ -706,6 +827,7 @@ ibus_im_context_class_init (IBusIMContextClass *class) static void ibus_im_context_class_fini (IBusIMContextClass *class) { +#if !GTK_CHECK_VERSION (3, 98, 4) if (_key_snooper_id != 0) { IDEBUG ("snooper is terminated."); #pragma GCC diagnostic push @@ -714,6 +836,7 @@ ibus_im_context_class_fini (IBusIMContextClass *class) #pragma GCC diagnostic pop _key_snooper_id = 0; } +#endif g_bus_unwatch_name (_daemon_name_watch_id); } @@ -849,7 +972,11 @@ ibus_im_context_finalize (GObject *obj) ibus_proxy_destroy ((IBusProxy *)ibusimcontext->ibuscontext); } +#if GTK_CHECK_VERSION (3, 98, 4) + ibus_im_context_set_client_widget ((GtkIMContext *)ibusimcontext, NULL); +#else ibus_im_context_set_client_window ((GtkIMContext *)ibusimcontext, NULL); +#endif if (ibusimcontext->slave) { g_object_unref (ibusimcontext->slave); @@ -864,8 +991,13 @@ ibus_im_context_finalize (GObject *obj) pango_attr_list_unref (ibusimcontext->preedit_attrs); } +#if GTK_CHECK_VERSION (3, 98, 4) + g_queue_free_full (ibusimcontext->events_queue, + (GDestroyNotify)gdk_event_unref); +#else g_queue_free_full (ibusimcontext->events_queue, (GDestroyNotify)gdk_event_free); +#endif G_OBJECT_CLASS(parent_class)->finalize (obj); } @@ -902,7 +1034,11 @@ ibus_im_context_clear_preedit_text (IBusIMContext *ibusimcontext) static gboolean ibus_im_context_filter_keypress (GtkIMContext *context, +#if GTK_CHECK_VERSION (3, 98, 4) + GdkEvent *event) +#else GdkEventKey *event) +#endif { IDEBUG ("%s", __FUNCTION__); @@ -917,6 +1053,15 @@ ibus_im_context_filter_keypress (GtkIMContext *context, if (!ibusimcontext->has_focus) return gtk_im_context_filter_keypress (ibusimcontext->slave, event); +#if GTK_CHECK_VERSION (3, 98, 4) + { + GdkModifierType state = gdk_event_get_modifier_state (event); + if (state & IBUS_HANDLED_MASK) + return TRUE; + if (state & IBUS_IGNORED_MASK) + return ibus_im_context_commit_event (ibusimcontext, event); + } +#else if (event->state & IBUS_HANDLED_MASK) return TRUE; @@ -931,17 +1076,28 @@ ibus_im_context_filter_keypress (GtkIMContext *context, if (ibusimcontext->client_window == NULL && event->window != NULL) gtk_im_context_set_client_window ((GtkIMContext *)ibusimcontext, event->window); +#endif _request_surrounding_text (ibusimcontext); +#if GTK_CHECK_VERSION (3, 98, 4) + ibusimcontext->time = gdk_event_get_time (event); + ibusimcontext->surface= gdk_event_get_surface (event); + ibusimcontext->device = gdk_event_get_device (event); + gdk_event_get_position (event, &ibusimcontext->x, &ibusimcontext->y); +#else ibusimcontext->time = event->time; +#endif if (ibusimcontext->ibuscontext) { - if (_process_key_event (ibusimcontext->ibuscontext, event)) + if (_process_key_event (ibusimcontext->ibuscontext, + event, + ibusimcontext)) { return TRUE; - else + } else { return gtk_im_context_filter_keypress (ibusimcontext->slave, event); + } } /* At this point we _should_ be waiting for the IBus context to be @@ -952,12 +1108,21 @@ ibus_im_context_filter_keypress (GtkIMContext *context, ibus_bus_is_connected (_bus) == FALSE, FALSE); g_queue_push_tail (ibusimcontext->events_queue, +#if GTK_CHECK_VERSION (3, 98, 4) + gdk_event_ref (event)); +#else gdk_event_copy ((GdkEvent *)event)); +#endif if (g_queue_get_length (ibusimcontext->events_queue) > MAX_QUEUED_EVENTS) { g_warning ("Events queue growing too big, will start to drop."); +#if GTK_CHECK_VERSION (3, 98, 4) + gdk_event_unref ((GdkEvent *) + g_queue_pop_head (ibusimcontext->events_queue)); +#else gdk_event_free ((GdkEvent *) g_queue_pop_head (ibusimcontext->events_queue)); +#endif } return TRUE; @@ -966,26 +1131,29 @@ ibus_im_context_filter_keypress (GtkIMContext *context, static void ibus_im_context_focus_in (GtkIMContext *context) { - IDEBUG ("%s", __FUNCTION__); - IBusIMContext *ibusimcontext = (IBusIMContext *) context; + GtkWidget *widget = NULL; + + IDEBUG ("%s", __FUNCTION__); if (ibusimcontext->has_focus) return; /* don't set focus on password entry */ +#if GTK_CHECK_VERSION (3, 98, 4) + widget = ibusimcontext->client_window; +#else if (ibusimcontext->client_window != NULL) { - GtkWidget *widget; - gdk_window_get_user_data (ibusimcontext->client_window, (gpointer *)&widget); - if (GTK_IS_ENTRY (widget) && - !gtk_entry_get_visibility (GTK_ENTRY (widget))) { - return; - } } +#endif + if (widget && GTK_IS_ENTRY (widget) && + !gtk_entry_get_visibility (GTK_ENTRY (widget))) { + return; + } /* Do not call gtk_im_context_focus_out() here. * google-chrome's notification popup window (Pushbullet) * takes the focus and the popup window disappears. @@ -1014,10 +1182,10 @@ ibus_im_context_focus_in (GtkIMContext *context) /* set_cursor_location_internal() will get origin from X server, * it blocks UI. So delay it to idle callback. */ - gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc) _set_cursor_location_internal, - g_object_ref (ibusimcontext), - (GDestroyNotify) g_object_unref); + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) _set_cursor_location_internal, + g_object_ref (ibusimcontext), + (GDestroyNotify) g_object_unref); /* retrieve the initial surrounding-text (regardless of whether * the current IBus engine needs surrounding-text) */ @@ -1122,7 +1290,7 @@ ibus_im_context_get_preedit_string (GtkIMContext *context, } -#if !GTK_CHECK_VERSION (3, 93, 0) +#if !GTK_CHECK_VERSION (3, 98, 4) /* Use the button-press-event signal until GtkIMContext always emits the reset * signal. * https://gitlab.gnome.org/GNOME/gtk/merge_requests/460 @@ -1171,8 +1339,15 @@ _connect_button_press_event (IBusIMContext *ibusimcontext, } #endif +#if GTK_CHECK_VERSION (3, 98, 4) static void -ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) +ibus_im_context_set_client_widget (GtkIMContext *context, + GtkWidget *client) +#else +static void +ibus_im_context_set_client_window (GtkIMContext *context, + GdkWindow *client) +#endif { IBusIMContext *ibusimcontext; @@ -1181,7 +1356,7 @@ ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) ibusimcontext = IBUS_IM_CONTEXT (context); if (ibusimcontext->client_window) { -#if !GTK_CHECK_VERSION (3, 93, 0) +#if !GTK_CHECK_VERSION (3, 98, 4) if (ibusimcontext->use_button_press_event) _connect_button_press_event (ibusimcontext, FALSE); #endif @@ -1191,26 +1366,41 @@ ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) if (client != NULL) { ibusimcontext->client_window = g_object_ref (client); -#if !GTK_CHECK_VERSION (3, 93, 0) +#if !GTK_CHECK_VERSION (3, 98, 4) if (!ibusimcontext->use_button_press_event) _connect_button_press_event (ibusimcontext, TRUE); #endif } +#if GTK_CHECK_VERSION (3, 98, 4) + if (ibusimcontext->slave) + gtk_im_context_set_client_widget (ibusimcontext->slave, client); +#else if (ibusimcontext->slave) gtk_im_context_set_client_window (ibusimcontext->slave, client); +#endif } static void _set_rect_scale_factor_with_window (GdkRectangle *area, +#if GTK_CHECK_VERSION (3, 98, 4) + GtkWidget *window) +#else GdkWindow *window) +#endif { #if GTK_CHECK_VERSION (3, 10, 0) int scale_factor; g_assert (area); +#if GTK_CHECK_VERSION (3, 98, 4) + g_assert (GTK_IS_WIDGET (window)); + + scale_factor = gtk_widget_get_scale_factor (window); +#else g_assert (GDK_IS_WINDOW (window)); scale_factor = gdk_window_get_scale_factor (window); +#endif area->x *= scale_factor; area->y *= scale_factor; area->width *= scale_factor; @@ -1230,6 +1420,7 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) area = ibusimcontext->cursor_area; +#if !GTK_CHECK_VERSION (3, 98, 4) #ifdef GDK_WINDOWING_WAYLAND if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) { gdouble px, py; @@ -1253,10 +1444,14 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) area.height); return FALSE; } +#endif #endif if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) { -#if GTK_CHECK_VERSION (2, 91, 0) +#if GTK_CHECK_VERSION (3, 98, 4) + area.x = 0; + area.y += gtk_widget_get_height (ibusimcontext->client_window); +#elif GTK_CHECK_VERSION (2, 91, 0) area.x = 0; area.y += gdk_window_get_height (ibusimcontext->client_window); #else @@ -1267,9 +1462,39 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) #endif } +#if GTK_CHECK_VERSION (3, 93, 0) + { +#if GTK_CHECK_VERSION (3, 98, 4) + GtkNative *native = gtk_widget_get_native ( + ibusimcontext->client_window); + GtkRoot *root = gtk_widget_get_root (ibusimcontext->client_window); + double nx, ny; + double px, py; + gtk_native_get_surface_transform (native, &nx, &ny); + px = (double)area.x + ibusimcontext->x - nx; + py = (double)area.y + ibusimcontext->y - ny; + gtk_widget_translate_coordinates (ibusimcontext->client_window, + (GtkWidget *)root, + px, py, + &px, &py); + area.x = (int)px; + area.y = (int)py; +#else + GtkNative *native = gtk_widget_get_native ( + ibusimcontext->client_window); + GdkSurface *surface = gtk_native_get_surface (native); + int root_x = 0; + int root_y = 0; + gdk_surface_get_position (surface, &root_x, &root_y); + area.x += root_x; + area.y += root_y; +#endif + } +#else gdk_window_get_root_coords (ibusimcontext->client_window, area.x, area.y, &area.x, &area.y); +#endif _set_rect_scale_factor_with_window (&area, ibusimcontext->client_window); ibus_input_context_set_cursor_location (ibusimcontext->ibuscontext, area.x, @@ -1326,7 +1551,11 @@ get_selection_anchor_point (IBusIMContext *ibusimcontext, if (ibusimcontext->client_window == NULL) { return cursor_pos; } +#if GTK_CHECK_VERSION (3, 98, 4) + widget = ibusimcontext->client_window; +#else gdk_window_get_user_data (ibusimcontext->client_window, (gpointer *)&widget); +#endif if (!GTK_IS_TEXT_VIEW (widget)){ return cursor_pos; @@ -1440,6 +1669,7 @@ _ibus_context_commit_text_cb (IBusInputContext *ibuscontext, _request_surrounding_text (ibusimcontext); } +#if !GTK_CHECK_VERSION (3, 98, 4) static gboolean _key_is_modifier (guint keyval) { @@ -1615,6 +1845,7 @@ _create_gdk_event (IBusIMContext *ibusimcontext, out: return event; } +#endif static void _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext, @@ -1624,9 +1855,32 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext, IBusIMContext *ibusimcontext) { IDEBUG ("%s", __FUNCTION__); +#if GTK_CHECK_VERSION (3, 98, 4) + int group = 0; + g_return_if_fail (GTK_IS_IM_CONTEXT (ibusimcontext)); + if (keycode == 0 && ibusimcontext->client_window) { + GdkDisplay *display = gtk_widget_get_display (ibusimcontext->client_window); + GdkKeymapKey *keys = NULL; + gint n_keys = 0; + if (!gdk_display_map_keyval (display, keyval, &keys, &n_keys)) + g_warning ("Failed to parse keycode from keyval %x", keyval); + keycode = keys->keycode; + group = keys->group; + } + gtk_im_context_filter_key ( + GTK_IM_CONTEXT (ibusimcontext), + (state & IBUS_RELEASE_MASK) ? FALSE : TRUE, + ibusimcontext->surface, + ibusimcontext->device, + ibusimcontext->time, + keycode, + (GdkModifierType)state, + group); +#else GdkEventKey *event = _create_gdk_event (ibusimcontext, keyval, keycode, state); gdk_event_put ((GdkEvent *)event); gdk_event_free ((GdkEvent *)event); +#endif } static void @@ -1660,7 +1914,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext, ibusimcontext->preedit_attrs = NULL; } -#if !GTK_CHECK_VERSION (3, 93, 0) +#if !GTK_CHECK_VERSION (3, 98, 4) if (!ibusimcontext->use_button_press_event && mode == IBUS_ENGINE_PREEDIT_COMMIT) { if (ibusimcontext->client_window) { @@ -1847,10 +2101,18 @@ _create_input_context_done (IBusBus *bus, } if (!g_queue_is_empty (ibusimcontext->events_queue)) { +#if GTK_CHECK_VERSION (3, 98, 4) + GdkEvent *event; +#else GdkEventKey *event; +#endif while ((event = g_queue_pop_head (ibusimcontext->events_queue))) { - _process_key_event (context, event); + _process_key_event (context, event, ibusimcontext); +#if GTK_CHECK_VERSION (3, 98, 4) + gdk_event_unref (event); +#else gdk_event_free ((GdkEvent *)event); +#endif } } } diff --git a/client/gtk4/Makefile.am b/client/gtk4/Makefile.am new file mode 100644 index 00000000..8d8b31db --- /dev/null +++ b/client/gtk4/Makefile.am @@ -0,0 +1,66 @@ +# vim:set noet ts=4: +# +# ibus - The Input Bus +# +# Copyright (c) 2020 Takao Fujiwara +# Copyright (c) 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 +# 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 + +libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + $(NULL) + +immoduledir = @GTK4_IM_MODULEDIR@ +immodule_LTLIBRARIES = libim-ibus.la + +libim_ibus_la_SOURCES = \ + ibusim.c \ + ibusimcontext.c \ + ibusimcontext.h \ + $(NULL) + +libim_ibus_la_DEPENDENCIES = $(libibus) + +libim_ibus_la_CFLAGS = \ + @GTK4_CFLAGS@ \ + @DBUS_CFLAGS@ \ + -DG_LOG_DOMAIN=\"IBUS\" \ + $(NULL) + +libim_ibus_la_LIBADD = \ + @GTK4_LIBS@ \ + @DBUS_LIBS@ \ + $(libibus) \ + $(NULL) +libim_ibus_la_LDFLAGS = \ + -avoid-version \ + -module \ + $(NULL) + +$(libibus): + (cd $(top_builddir)/src; make ) + +EXTRA_DIST = \ + $(NULL) + +test: all + GTK_IM_MODULE=ibus gedit + +-include $(top_srcdir)/git.mk diff --git a/client/gtk4/ibusim.c b/client/gtk4/ibusim.c new file mode 100644 index 00000000..5ecf9778 --- /dev/null +++ b/client/gtk4/ibusim.c @@ -0,0 +1,52 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* vim:set et ts=4: */ +/* ibus - The Input Bus + * Copyright (C) 2008-2010 Peng Huang + * 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 + * 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 + */ + +#include +#include +#include +#include "ibusimcontext.h" + +G_MODULE_EXPORT void +g_io_im_ibus_load (GTypeModule *type_module) +{ + static gboolean inited = FALSE; + + if (!inited) { + ibus_init (); + ibus_im_context_register_type (type_module); + g_io_extension_point_implement ("gtk-im-module", + IBUS_TYPE_IM_CONTEXT, + "ibus", + 50); + inited = TRUE; + } + /* make module resident */ + g_type_module_use (type_module); +} + +G_MODULE_EXPORT void +g_io_im_ibus_unload (GTypeModule *type_module) +{ + g_type_module_unuse (type_module); +} + diff --git a/client/gtk4/ibusimcontext.c b/client/gtk4/ibusimcontext.c new file mode 120000 index 00000000..41896f05 --- /dev/null +++ b/client/gtk4/ibusimcontext.c @@ -0,0 +1 @@ +../gtk2/ibusimcontext.c \ No newline at end of file diff --git a/client/gtk4/ibusimcontext.h b/client/gtk4/ibusimcontext.h new file mode 120000 index 00000000..29759883 --- /dev/null +++ b/client/gtk4/ibusimcontext.h @@ -0,0 +1 @@ +../gtk2/ibusimcontext.h \ No newline at end of file diff --git a/configure.ac b/configure.ac index 9ed5cb66..ffea3317 100644 --- a/configure.ac +++ b/configure.ac @@ -193,6 +193,15 @@ AC_ARG_ENABLE(gtk3, ) AM_CONDITIONAL([ENABLE_GTK3], [test x"$enable_gtk3" = x"yes"]) +# --enable-gtk4 option. +AC_ARG_ENABLE(gtk4, + AS_HELP_STRING([--enable-gtk4], + [Build gtk4 im module]), + [enable_gtk4=$enableval], + [enable_gtk4=no] +) +AM_CONDITIONAL([ENABLE_GTK4], [test x"$enable_gtk4" = x"yes"]) + # --disable-xim option. AC_ARG_ENABLE(xim, AS_HELP_STRING([--disable-xim], @@ -257,6 +266,18 @@ if test x"$enable_gdk3_wayland" != x"yes"; then fi AM_CONDITIONAL([ENABLE_GDK3_WAYLAND], [test x"$enable_gdk3_wayland" = x"yes"]) +if test x"$enable_gtk4" = x"yes"; then + # check for gtk4 + PKG_CHECK_MODULES(GTK4, [ + gtk4 + ]) + + gtk4_binary_version=`$PKG_CONFIG --variable=gtk_binary_version gtk4` + GTK4_IM_MODULEDIR="$libdir"/gtk-4.0/$gtk4_binary_version/immodules +else + enable_gtk4="no (disabled, use --enable-gtk4 to enable)" +fi + if test x"$enable_xim" = x"yes"; then # Check for x11 PKG_CHECK_MODULES(X11, [ @@ -478,6 +499,14 @@ AC_ARG_WITH(gtk3-im-module-dir, ) AC_SUBST(GTK3_IM_MODULEDIR) +# Define gtk4 immodule dir. +AC_ARG_WITH(gtk4-im-module-dir, + AS_HELP_STRING([--with-gtk4-im-module-dir[=DIR]], + [Select gtk4 immodule dir]), + GTK4_IM_MODULEDIR=$with_gtk4_im_module_dir +) +AC_SUBST(GTK4_IM_MODULEDIR) + if test x"$enable_python" = x"yes"; then # Check for dbus-python. AC_ARG_ENABLE(dbus-python-check, @@ -737,6 +766,7 @@ ibus.spec client/Makefile client/gtk2/Makefile client/gtk3/Makefile +client/gtk4/Makefile client/x11/Makefile client/wayland/Makefile src/Makefile @@ -786,8 +816,10 @@ Build options: Enable python2 $enable_python2 Gtk2 immodule dir $GTK2_IM_MODULEDIR Gtk3 immodule dir $GTK3_IM_MODULEDIR + Gtk4 immodule dir $GTK4_IM_MODULEDIR Build gtk2 immodule $enable_gtk2 Build gtk3 immodule $enable_gtk3 + Build gtk4 immodule $enable_gtk4 Build XIM agent server $enable_xim Build wayland support $enable_wayland Build gdk3 wayland support $enable_gdk3_wayland -- 2.28.0 From d0a47c3c82b1a0c263ff8b95f9cf5c0a5d1f228d Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Fri, 8 Jan 2021 18:48:13 +0900 Subject: [PATCH] client/gtk2: Add XTranslateCoordinates for GTK4 X11 coordinate GdkWindow had the absolute coordiante in the private class in GTK3 but the absolute coordiane no longer exists in GTK4 for Wayland. Now get the toplevel window coordiante for the warkaround in GTK4 but the coordiante of the inner widgets is no longer available too. BUG=https://gitlab.gnome.org/GNOME/gtk/-/issues/3024#note_987835 --- client/gtk2/ibusimcontext.c | 47 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index a23fc2e3..e153081d 100644 --- a/client/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c @@ -39,6 +39,13 @@ #endif #endif +#ifdef GDK_WINDOWING_X11 +#if GTK_CHECK_VERSION (3, 98, 4) +#include +#include +#endif +#endif + #if !GTK_CHECK_VERSION (2, 91, 0) # define DEPRECATED_GDK_KEYSYMS 1 #endif @@ -1462,24 +1469,33 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) #endif } -#if GTK_CHECK_VERSION (3, 93, 0) - { #if GTK_CHECK_VERSION (3, 98, 4) +#ifdef GDK_WINDOWING_X11 + GdkDisplay *display = gtk_widget_get_display (ibusimcontext->client_window); + if (GDK_IS_X11_DISPLAY (display)) { + Display *xdisplay = gdk_x11_display_get_xdisplay (display); + Window root_window = gdk_x11_display_get_xrootwindow (display); GtkNative *native = gtk_widget_get_native ( ibusimcontext->client_window); - GtkRoot *root = gtk_widget_get_root (ibusimcontext->client_window); - double nx, ny; - double px, py; - gtk_native_get_surface_transform (native, &nx, &ny); - px = (double)area.x + ibusimcontext->x - nx; - py = (double)area.y + ibusimcontext->y - ny; - gtk_widget_translate_coordinates (ibusimcontext->client_window, - (GtkWidget *)root, - px, py, - &px, &py); - area.x = (int)px; - area.y = (int)py; -#else + GdkSurface *surface = gtk_native_get_surface (native); + /* The window is the toplevel window but not the inner text widget. + * Unfortunatelly GTK4 cannot get the coordinate of the text widget. + */ + Window window = gdk_x11_surface_get_xid (surface); + Window child; + int x, y; + XTranslateCoordinates (xdisplay, window, root_window, + 0, 0, &x, &y, &child); + XWindowAttributes xwa; + XGetWindowAttributes (xdisplay, window, &xwa); + area.x = x - xwa.x + area.x; + area.y = y - xwa.y + area.y; + area.width = xwa.width; + area.height = xwa.height; + } +#endif +#elif GTK_CHECK_VERSION (3, 93, 0) + { GtkNative *native = gtk_widget_get_native ( ibusimcontext->client_window); GdkSurface *surface = gtk_native_get_surface (native); @@ -1488,7 +1504,6 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) gdk_surface_get_position (surface, &root_x, &root_y); area.x += root_x; area.y += root_y; -#endif } #else gdk_window_get_root_coords (ibusimcontext->client_window, -- 2.28.0 From ef4c5c7ef790ce1f80e94a5463e110ed4bae254e Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Wed, 20 Jan 2021 17:26:47 +0900 Subject: [PATCH] setup: Search engine name directly Currently users can search language names only in the language list in ibus-setup. After a language is selected and open, engine names can be searched. Now engine names also can be searched in the language list. --- setup/enginedialog.py | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/setup/enginedialog.py b/setup/enginedialog.py index 72deada8..e1c322bf 100644 --- a/setup/enginedialog.py +++ b/setup/enginedialog.py @@ -4,7 +4,7 @@ # ibus - The Input Bus # # Copyright (c) 2015 Peng Huang -# Copyright (c) 2015-2019 Takao Fujiwara +# Copyright (c) 2015-2021 Takao Fujiwara # Copyright (c) 2013-2015 Red Hat, Inc. # # This program is free software; you can redistribute it and/or @@ -112,15 +112,20 @@ class EngineDialog(Gtk.Dialog): return False if self.__filter_word == None: return True + if row.back: + return True - name = row.name.lower() - untrans = row.untrans.lower() - if self.__filter_word != None: - word = self.__filter_word.lower() - if name.startswith(word): - return True - if untrans.startswith(word): - return True + word = self.__filter_word.lower() + if word in row.name.lower(): + return True + if word in row.untrans.lower(): + return True + if row.lang_info and row.name in self.__engines_for_lang: + for row_e in self.__engines_for_lang[row.name]: + if word in row_e.name.lower(): + return True + if word in row_e.untrans.lower(): + return True return False @@ -129,11 +134,9 @@ class EngineDialog(Gtk.Dialog): self.__show_more() return if row.back: - self.__filter_entry.set_text('') self.__show_lang_rows() return if row.lang_info: - self.__filter_entry.set_text('') self.__show_engines_for_lang(row) return @@ -232,6 +235,7 @@ class EngineDialog(Gtk.Dialog): description = i18n.gettext_engine_description(engine) row = self.__list_box_row_new(longname) row.untrans = engine.get_longname() + row.rank = engine.get_rank() row.set_tooltip_text(description) row.engine = engine widget = self.__padded_label_new(longname, @@ -260,16 +264,13 @@ class EngineDialog(Gtk.Dialog): lang = row.name def cmp_engine(a, b): - if a.get_rank() == b.get_rank(): - a_longname = i18n.gettext_engine_longname(a) - b_longname = i18n.gettext_engine_longname(b) - return locale.strcoll(a_longname, b_longname) - return int(b.get_rank() - a.get_rank()) + if a.rank == b.rank: + return locale.strcoll(a.name, b.name) + return int(b.rank - a.rank) self.__engines_for_lang[lang].sort( key = functools.cmp_to_key(cmp_engine)) - for e in self.__engines_for_lang[lang]: - row = self.__engine_row_new(e) + for row in self.__engines_for_lang[lang]: self.__list.add(row) @@ -329,7 +330,8 @@ class EngineDialog(Gtk.Dialog): if l not in self.__engines_for_lang: self.__engines_for_lang[l] = [] i18n.init_textdomain(e.get_textdomain()) - self.__engines_for_lang[l].append(e) + row = self.__engine_row_new(e) + self.__engines_for_lang[l].append(row) # Retrieve Untranslated language names. untrans = IBus.get_untranslated_language_name(e.get_language()) -- 2.28.0