public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Takao Fujiwara <tfujiwar@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/ibus] autotool: Enabled panel extension in Wayland
Date: Sun, 31 May 2026 02:06:46 GMT [thread overview]
Message-ID: <178019320656.1.9013830562427065902.rpms-ibus-cf670af51697@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/ibus
Branch : autotool
Commit : cf670af51697a45d743bcbb8f9330be94bc62fdb
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date : 2018-02-27T15:47:19+09:00
Stats : +1401/-1 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/ibus/c/cf670af51697a45d743bcbb8f9330be94bc62fdb?branch=autotool
Log:
Enabled panel extension in Wayland
---
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
index 8d1fa9f..fa81971 100644
--- a/ibus-HEAD.patch
+++ b/ibus-HEAD.patch
@@ -8623,3 +8623,1399 @@ index 50700121..1fbf6cfc 100644
--
2.14.3
+From 7ccbd21ca7d163cdd71dc6c0405d8a32d63d324d Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Tue, 27 Feb 2018 14:06:30 +0900
+Subject: [PATCH 1/2] Disable panel extension for gdm user
+
+The gdm user's process is also running while the login user's process
+is running so the double panel extensions are better to be avoided for
+the memory usage.
+
+Review URL: https://codereview.appspot.com/340330044
+---
+ bus/main.c | 49 ++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 30 insertions(+), 19 deletions(-)
+
+diff --git a/bus/main.c b/bus/main.c
+index 5b2589b1..fe603778 100644
+--- a/bus/main.c
++++ b/bus/main.c
+@@ -47,6 +47,10 @@ static gchar *panel_extension = "default";
+ static gchar *config = "default";
+ static gchar *desktop = "gnome";
+
++static gchar *panel_extension_disable_users[] = {
++ "gdm"
++};
++
+ static void
+ show_version_and_quit (void)
+ {
+@@ -170,6 +174,9 @@ _sig_usr2_handler (int sig)
+ gint
+ main (gint argc, gchar **argv)
+ {
++ int i;
++ const gchar *username = ibus_get_user_name ();
++
+ setlocale (LC_ALL, "");
+
+ GOptionContext *context = g_option_context_new ("- ibus daemon");
+@@ -194,9 +201,7 @@ main (gint argc, gchar **argv)
+
+ /* check uid */
+ {
+- const gchar *username = ibus_get_user_name ();
+- uid_t uid = getuid ();
+- struct passwd *pwd = getpwuid (uid);
++ struct passwd *pwd = getpwuid (getuid ());
+
+ if (pwd == NULL || g_strcmp0 (pwd->pw_name, username) != 0) {
+ g_printerr ("Please run ibus-daemon with login user! Do not run ibus-daemon with sudo or su.\n");
+@@ -237,6 +242,12 @@ main (gint argc, gchar **argv)
+ }
+
+ bus_server_init ();
++ for (i = 0; i < G_N_ELEMENTS(panel_extension_disable_users); i++) {
++ if (!g_strcmp0 (username, panel_extension_disable_users[i]) != 0) {
++ panel_extension = "disable";
++ break;
++ }
++ }
+ if (!single) {
+ /* execute config component */
+ if (g_strcmp0 (config, "default") == 0) {
+@@ -271,25 +282,25 @@ main (gint argc, gchar **argv)
+ if (!execute_cmdline (panel))
+ exit (-1);
+ }
++ }
+
+ #ifdef EMOJI_DICT
+- if (g_strcmp0 (panel_extension, "default") == 0) {
+- BusComponent *component;
+- component = bus_ibus_impl_lookup_component_by_name (
+- BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION);
+- if (component) {
+- bus_component_set_restart (component, restart);
+- }
+- if (component == NULL ||
+- !bus_component_start (component, g_verbose)) {
+- g_printerr ("Can not execute default panel program\n");
+- exit (-1);
+- }
+- } else if (g_strcmp0 (panel_extension, "disable") != 0 &&
+- g_strcmp0 (panel_extension, "") != 0) {
+- if (!execute_cmdline (panel_extension))
+- exit (-1);
++ if (g_strcmp0 (panel_extension, "default") == 0) {
++ BusComponent *component;
++ component = bus_ibus_impl_lookup_component_by_name (
++ BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION);
++ if (component) {
++ bus_component_set_restart (component, restart);
++ }
++ if (component == NULL ||
++ !bus_component_start (component, g_verbose)) {
++ g_printerr ("Can not execute default panel program\n");
++ exit (-1);
+ }
++ } else if (g_strcmp0 (panel_extension, "disable") != 0 &&
++ g_strcmp0 (panel_extension, "") != 0) {
++ if (!execute_cmdline (panel_extension))
++ exit (-1);
+ }
+ #endif
+
+--
+2.14.3
+
+From c57b7c34d75871db172e023b0094b979000f62fc Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Tue, 27 Feb 2018 14:10:29 +0900
+Subject: [PATCH 2/2] Enable emoji keybinding in Wayland
+
+XI2 keybinding does not work for the root window in Wayland because
+of a security issue maybe. Now I think to move the keybinding in
+ibus-extension-gtk3 to each IBusEngine.
+
+FIXME: Unfortunatelly gtk_get_current_event_time() cannot get time
+for the delayed DBus events and gtk_window_move() does not work for
+GtkDialog without a parent window in Wayland.
+
+R=Shawn.P.Huang@gmail.com
+
+Review URL: https://codereview.appspot.com/333700043
+---
+ bus/engineproxy.c | 19 +-
+ bus/ibusimpl.c | 47 +++-
+ bus/inputcontext.c | 29 ++-
+ src/Makefile.am | 2 +
+ src/ibus.h | 1 +
+ src/ibusaccelgroup.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/ibusaccelgroup.h | 51 +++++
+ src/ibusengine.c | 179 +++++++++++++++-
+ ui/gtk3/emojier.vala | 1 +
+ ui/gtk3/extension.vala | 5 +-
+ ui/gtk3/panelbinding.vala | 65 ++----
+ 11 files changed, 863 insertions(+), 65 deletions(-)
+ create mode 100644 src/ibusaccelgroup.c
+ create mode 100644 src/ibusaccelgroup.h
+
+diff --git a/bus/engineproxy.c b/bus/engineproxy.c
+index cd4d54fd..175aec56 100644
+--- a/bus/engineproxy.c
++++ b/bus/engineproxy.c
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2015-2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -90,6 +90,7 @@ enum {
+ CURSOR_DOWN_LOOKUP_TABLE,
+ REGISTER_PROPERTIES,
+ UPDATE_PROPERTY,
++ PANEL_EXTENSION,
+ LAST_SIGNAL,
+ };
+
+@@ -370,6 +371,17 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class)
+ 1,
+ IBUS_TYPE_PROPERTY);
+
++ engine_signals[PANEL_EXTENSION] =
++ g_signal_new (I_("panel-extension"),
++ G_TYPE_FROM_CLASS (class),
++ G_SIGNAL_RUN_LAST,
++ 0,
++ NULL, NULL,
++ bus_marshal_VOID__VARIANT,
++ G_TYPE_NONE,
++ 1,
++ G_TYPE_VARIANT);
++
+ text_empty = ibus_text_new_from_static_string ("");
+ g_object_ref_sink (text_empty);
+
+@@ -631,6 +643,11 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ return;
+ }
+
++ if (g_strcmp0 (signal_name, "PanelExtension") == 0) {
++ g_signal_emit (engine, engine_signals[PANEL_EXTENSION], 0, parameters);
++ return;
++ }
++
+ g_return_if_reached ();
+ }
+
+diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
+index 58d205cf..a4ce3d9d 100644
+--- a/bus/ibusimpl.c
++++ b/bus/ibusimpl.c
+@@ -302,9 +302,8 @@ _panel_destroy_cb (BusPanelProxy *panel,
+ }
+
+ static void
+-_panel_panel_extension_cb (BusPanelProxy *panel,
+- GVariant *parameters,
+- BusIBusImpl *ibus)
++bus_ibus_impl_panel_extension_received (BusIBusImpl *ibus,
++ GVariant *parameters)
+ {
+ if (!ibus->extension) {
+ g_warning ("Panel extension is not running.");
+@@ -323,6 +322,14 @@ _panel_panel_extension_cb (BusPanelProxy *panel,
+ -1, NULL, NULL, NULL);
+ }
+
++static void
++_panel_panel_extension_cb (BusPanelProxy *panel,
++ GVariant *parameters,
++ BusIBusImpl *ibus)
++{
++ bus_ibus_impl_panel_extension_received (ibus, parameters);
++}
++
+ static void
+ _registry_changed_cb (IBusRegistry *registry,
+ BusIBusImpl *ibus)
+@@ -642,6 +649,21 @@ bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl *ibus,
+ NULL);
+ }
+
++static void
++_context_panel_extension_cb (BusInputContext *context,
++ GVariant *parameters,
++ BusIBusImpl *ibus)
++{
++ bus_ibus_impl_panel_extension_received (ibus, parameters);
++}
++
++const static struct {
++ const gchar *name;
++ GCallback callback;
++} context_signals [] = {
++ { "panel-extension", G_CALLBACK (_context_panel_extension_cb) }
++};
++
+ /**
+ * bus_ibus_impl_set_focused_context:
+ *
+@@ -651,6 +673,11 @@ static void
+ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
+ BusInputContext *context)
+ {
++ gint i;
++ BusEngineProxy *engine = NULL;
++ guint purpose = 0;
++ guint hints = 0;
++
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (context == NULL || BUS_IS_INPUT_CONTEXT (context));
+ g_assert (context == NULL || bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS);
+@@ -660,10 +687,6 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
+ return;
+ }
+
+- BusEngineProxy *engine = NULL;
+- guint purpose = 0;
+- guint hints = 0;
+-
+ if (ibus->focused_context) {
+ if (ibus->use_global_engine) {
+ /* dettach engine from the focused context */
+@@ -681,6 +704,10 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
+
+ bus_input_context_get_content_type (ibus->focused_context,
+ &purpose, &hints);
++ for (i = 0; i < G_N_ELEMENTS(context_signals); i++) {
++ g_signal_handlers_disconnect_by_func (ibus->focused_context,
++ context_signals[i].callback, ibus);
++ }
+ g_object_unref (ibus->focused_context);
+ ibus->focused_context = NULL;
+ }
+@@ -698,6 +725,12 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
+ bus_input_context_set_engine (context, engine);
+ bus_input_context_enable (context);
+ }
++ for (i = 0; i < G_N_ELEMENTS(context_signals); i++) {
++ g_signal_connect (ibus->focused_context,
++ context_signals[i].name,
++ context_signals[i].callback,
++ ibus);
++ }
+
+ if (ibus->panel != NULL)
+ bus_panel_proxy_focus_in (ibus->panel, context);
+diff --git a/bus/inputcontext.c b/bus/inputcontext.c
+index 4f2ecafc..a957d107 100644
+--- a/bus/inputcontext.c
++++ b/bus/inputcontext.c
+@@ -127,6 +127,7 @@ enum {
+ ENGINE_CHANGED,
+ REQUEST_ENGINE,
+ SET_CONTENT_TYPE,
++ PANEL_EXTENSION,
+ LAST_SIGNAL,
+ };
+
+@@ -598,6 +599,17 @@ bus_input_context_class_init (BusInputContextClass *class)
+ G_TYPE_UINT,
+ G_TYPE_UINT);
+
++ context_signals[PANEL_EXTENSION] =
++ g_signal_new (I_("panel-extension"),
++ G_TYPE_FROM_CLASS (class),
++ G_SIGNAL_RUN_LAST,
++ 0,
++ NULL, NULL,
++ bus_marshal_VOID__VARIANT,
++ G_TYPE_NONE,
++ 1,
++ G_TYPE_VARIANT);
++
+ text_empty = ibus_text_new_from_string ("");
+ g_object_ref_sink (text_empty);
+ lookup_table_empty = ibus_lookup_table_new (9 /* page size */, 0, FALSE, FALSE);
+@@ -2102,6 +2114,20 @@ _engine_update_property_cb (BusEngineProxy *engine,
+ bus_input_context_update_property (context, prop);
+ }
+
++/**
++ * _engine_panel_extension_cb:
++ *
++ * A function to be called when "panel-extension" glib signal is sent
++ * from the engine object.
++ */
++static void
++_engine_panel_extension_cb (BusEngineProxy *engine,
++ GVariant *parameters,
++ BusInputContext *context)
++{
++ g_signal_emit (context, context_signals[PANEL_EXTENSION], 0, parameters);
++}
++
+ #define DEFINE_FUNCTION(name) \
+ static void \
+ _engine_##name##_cb (BusEngineProxy *engine, \
+@@ -2244,7 +2270,8 @@ const static struct {
+ { "cursor-down-lookup-table", G_CALLBACK (_engine_cursor_down_lookup_table_cb) },
+ { "register-properties", G_CALLBACK (_engine_register_properties_cb) },
+ { "update-property", G_CALLBACK (_engine_update_property_cb) },
+- { "destroy", G_CALLBACK (_engine_destroy_cb) },
++ { "panel-extension", G_CALLBACK (_engine_panel_extension_cb) },
++ { "destroy", G_CALLBACK (_engine_destroy_cb) }
+ };
+
+ static void
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 72ec05ab..6a62e0f0 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -72,6 +72,7 @@ libibus_1_0_la_LDFLAGS = \
+ $(NULL)
+
+ ibus_sources = \
++ ibusaccelgroup.c \
+ ibusattribute.c \
+ ibusattrlist.c \
+ ibusbus.c \
+@@ -122,6 +123,7 @@ ibus_enumtypes_sources = \
+ $(NULL)
+ ibus_headers = \
+ ibus.h \
++ ibusaccelgroup.h \
+ ibusattribute.h \
+ ibusattrlist.h \
+ ibusbus.h \
+diff --git a/src/ibus.h b/src/ibus.h
+index b15dded9..256d57ba 100644
+--- a/src/ibus.h
++++ b/src/ibus.h
+@@ -60,6 +60,7 @@
+ #include <ibusemoji.h>
+ #include <ibusunicode.h>
+ #include <ibusxevent.h>
++#include <ibusaccelgroup.h>
+
+ #ifndef IBUS_DISABLE_DEPRECATED
+ #include <ibuskeysyms-compat.h>
+diff --git a/src/ibusaccelgroup.c b/src/ibusaccelgroup.c
+new file mode 100644
+index 00000000..8a81597e
+--- /dev/null
++++ b/src/ibusaccelgroup.c
+@@ -0,0 +1,529 @@
++/* GTK - The GIMP Toolkit
++ * Copyright (C) 1998, 2001 Tim Janik
++ *
++ * 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 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 <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
++ * file for a list of people on the GTK+ Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "config.h"
++#include <string.h>
++#include <stdlib.h>
++
++#include "ibusaccelgroup.h"
++#include "ibuskeys.h"
++#include "ibuskeysyms.h"
++
++
++/* for _gtk_get_primary_accel_mod() */
++#define _IBUS_GET_PRIMARY_ACCEL_MOD IBUS_CONTROL_MASK
++
++/**
++ * SECTION: ibusaccelgroup
++ * @short_description: Groups of global keyboard accelerators for an
++ * entire GtkWindow
++ * @title: Accelerator Groups
++ * @stability: Unstable
++ *
++ * Provides ibus_accelerator_parse()
++ */
++
++
++/**
++ * ibus_accelerator_valid:
++ * @keyval: a GDK keyval
++ * @modifiers: modifier mask
++ *
++ * Determines whether a given keyval and modifier mask constitute
++ * a valid keyboard accelerator. For example, the #IBUS_KEY_a keyval
++ * plus #IBUS_CONTROL_MASK is valid - this is a “Ctrl+a” accelerator.
++ * But, you can't, for instance, use the #IBUS_KEY_Control_L keyval
++ * as an accelerator.
++ *
++ * Returns: %TRUE if the accelerator is valid
++ */
++gboolean
++ibus_accelerator_valid (guint keyval,
++ IBusModifierType modifiers)
++{
++ static const guint invalid_accelerator_vals[] = {
++ IBUS_KEY_Shift_L, IBUS_KEY_Shift_R, IBUS_KEY_Shift_Lock,
++ IBUS_KEY_Caps_Lock, IBUS_KEY_ISO_Lock, IBUS_KEY_Control_L,
++ IBUS_KEY_Control_R, IBUS_KEY_Meta_L, IBUS_KEY_Meta_R,
++ IBUS_KEY_Alt_L, IBUS_KEY_Alt_R, IBUS_KEY_Super_L, IBUS_KEY_Super_R,
++ IBUS_KEY_Hyper_L, IBUS_KEY_Hyper_R, IBUS_KEY_ISO_Level3_Shift,
++ IBUS_KEY_ISO_Next_Group, IBUS_KEY_ISO_Prev_Group,
++ IBUS_KEY_ISO_First_Group, IBUS_KEY_ISO_Last_Group,
++ IBUS_KEY_Mode_switch, IBUS_KEY_Num_Lock, IBUS_KEY_Multi_key,
++ IBUS_KEY_Scroll_Lock, IBUS_KEY_Sys_Req,
++ IBUS_KEY_Tab, IBUS_KEY_ISO_Left_Tab, IBUS_KEY_KP_Tab,
++ IBUS_KEY_First_Virtual_Screen, IBUS_KEY_Prev_Virtual_Screen,
++ IBUS_KEY_Next_Virtual_Screen, IBUS_KEY_Last_Virtual_Screen,
++ IBUS_KEY_Terminate_Server, IBUS_KEY_AudibleBell_Enable,
++ 0
++ };
++ static const guint invalid_unmodified_vals[] = {
++ IBUS_KEY_Up, IBUS_KEY_Down, IBUS_KEY_Left, IBUS_KEY_Right,
++ IBUS_KEY_KP_Up, IBUS_KEY_KP_Down, IBUS_KEY_KP_Left, IBUS_KEY_KP_Right,
++ 0
++ };
++ const guint *ac_val;
++
++ modifiers &= IBUS_MODIFIER_MASK;
++
++ if (keyval <= 0xFF)
++ return keyval >= 0x20;
++
++ ac_val = invalid_accelerator_vals;
++ while (*ac_val) {
++ if (keyval == *ac_val++)
++ return FALSE;
++ }
++
++ if (!modifiers) {
++ ac_val = invalid_unmodified_vals;
++ while (*ac_val) {
++ if (keyval == *ac_val++)
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++static inline gboolean
++is_alt (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'a' || string[1] == 'A') &&
++ (string[2] == 'l' || string[2] == 'L') &&
++ (string[3] == 't' || string[3] == 'T') &&
++ (string[4] == '>'));
++}
++
++static inline gboolean
++is_ctl (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'c' || string[1] == 'C') &&
++ (string[2] == 't' || string[2] == 'T') &&
++ (string[3] == 'l' || string[3] == 'L') &&
++ (string[4] == '>'));
++}
++
++static inline gboolean
++is_modx (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'm' || string[1] == 'M') &&
++ (string[2] == 'o' || string[2] == 'O') &&
++ (string[3] == 'd' || string[3] == 'D') &&
++ (string[4] >= '1' && string[4] <= '5') &&
++ (string[5] == '>'));
++}
++
++static inline gboolean
++is_ctrl (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'c' || string[1] == 'C') &&
++ (string[2] == 't' || string[2] == 'T') &&
++ (string[3] == 'r' || string[3] == 'R') &&
++ (string[4] == 'l' || string[4] == 'L') &&
++ (string[5] == '>'));
++}
++
++static inline gboolean
++is_shft (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 's' || string[1] == 'S') &&
++ (string[2] == 'h' || string[2] == 'H') &&
++ (string[3] == 'f' || string[3] == 'F') &&
++ (string[4] == 't' || string[4] == 'T') &&
++ (string[5] == '>'));
++}
++
++static inline gboolean
++is_shift (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 's' || string[1] == 'S') &&
++ (string[2] == 'h' || string[2] == 'H') &&
++ (string[3] == 'i' || string[3] == 'I') &&
++ (string[4] == 'f' || string[4] == 'F') &&
++ (string[5] == 't' || string[5] == 'T') &&
++ (string[6] == '>'));
++}
++
++static inline gboolean
++is_control (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'c' || string[1] == 'C') &&
++ (string[2] == 'o' || string[2] == 'O') &&
++ (string[3] == 'n' || string[3] == 'N') &&
++ (string[4] == 't' || string[4] == 'T') &&
++ (string[5] == 'r' || string[5] == 'R') &&
++ (string[6] == 'o' || string[6] == 'O') &&
++ (string[7] == 'l' || string[7] == 'L') &&
++ (string[8] == '>'));
++}
++
++static inline gboolean
++is_release (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'r' || string[1] == 'R') &&
++ (string[2] == 'e' || string[2] == 'E') &&
++ (string[3] == 'l' || string[3] == 'L') &&
++ (string[4] == 'e' || string[4] == 'E') &&
++ (string[5] == 'a' || string[5] == 'A') &&
++ (string[6] == 's' || string[6] == 'S') &&
++ (string[7] == 'e' || string[7] == 'E') &&
++ (string[8] == '>'));
++}
++
++static inline gboolean
++is_meta (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'm' || string[1] == 'M') &&
++ (string[2] == 'e' || string[2] == 'E') &&
++ (string[3] == 't' || string[3] == 'T') &&
++ (string[4] == 'a' || string[4] == 'A') &&
++ (string[5] == '>'));
++}
++
++static inline gboolean
++is_super (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 's' || string[1] == 'S') &&
++ (string[2] == 'u' || string[2] == 'U') &&
++ (string[3] == 'p' || string[3] == 'P') &&
++ (string[4] == 'e' || string[4] == 'E') &&
++ (string[5] == 'r' || string[5] == 'R') &&
++ (string[6] == '>'));
++}
++
++static inline gboolean
++is_hyper (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'h' || string[1] == 'H') &&
++ (string[2] == 'y' || string[2] == 'Y') &&
++ (string[3] == 'p' || string[3] == 'P') &&
++ (string[4] == 'e' || string[4] == 'E') &&
++ (string[5] == 'r' || string[5] == 'R') &&
++ (string[6] == '>'));
++}
++
++static inline gboolean
++is_primary (const gchar *string)
++{
++ return ((string[0] == '<') &&
++ (string[1] == 'p' || string[1] == 'P') &&
++ (string[2] == 'r' || string[2] == 'R') &&
++ (string[3] == 'i' || string[3] == 'I') &&
++ (string[4] == 'm' || string[4] == 'M') &&
++ (string[5] == 'a' || string[5] == 'A') &&
++ (string[6] == 'r' || string[6] == 'R') &&
++ (string[7] == 'y' || string[7] == 'Y') &&
++ (string[8] == '>'));
++}
++
++static inline gboolean
++is_keycode (const gchar *string)
++{
++ return (string[0] == '0' &&
++ string[1] == 'x' &&
++ g_ascii_isxdigit (string[2]) &&
++ g_ascii_isxdigit (string[3]));
++}
++
++/**
++ * ibus_accelerator_parse:
++ * @accelerator: string representing an accelerator
++ * @accelerator_key: (out) (allow-none): return location for accelerator
++ * keyval, or %NULL
++ * @accelerator_mods: (out) (allow-none): return location for accelerator
++ * modifier mask, %NULL
++ *
++ * Parses a string representing an accelerator. The format looks like
++ * “<Control>a” or “<Shift><Alt>F1” or “<Release>z” (the last one is
++ * for key release).
++ *
++ * The parser is fairly liberal and allows lower or upper case, and also
++ * abbreviations such as “<Ctl>” and “<Ctrl>”. Key names are parsed using
++ * gdk_keyval_from_name(). For character keys the name is not the symbol,
++ * but the lowercase name, e.g. one would use “<Ctrl>minus” instead of
++ * “<Ctrl>-”.
++ *
++ * If the parse fails, @accelerator_key and @accelerator_mods will
++ * be set to 0 (zero).
++ *
++ * Since: 1.5.18
++ */
++void
++ibus_accelerator_parse (const gchar *accelerator,
++ guint *accelerator_key,
++ IBusModifierType *accelerator_mods)
++{
++ guint keyval;
++ IBusModifierType mods;
++ gint len;
++ gboolean error;
++
++ if (accelerator_key)
++ *accelerator_key = 0;
++ if (accelerator_mods)
++ *accelerator_mods = 0;
++ g_return_if_fail (accelerator != NULL);
++
++ error = FALSE;
++ keyval = 0;
++ mods = 0;
++ len = strlen (accelerator);
++ while (len) {
++ if (*accelerator == '<') {
++ if (len >= 9 && is_release (accelerator)) {
++ accelerator += 9;
++ len -= 9;
++ mods |= IBUS_RELEASE_MASK;
++ } else if (len >= 9 && is_primary (accelerator)) {
++ accelerator += 9;
++ len -= 9;
++ mods |= _IBUS_GET_PRIMARY_ACCEL_MOD;
++ } else if (len >= 9 && is_control (accelerator)) {
++ accelerator += 9;
++ len -= 9;
++ mods |= IBUS_CONTROL_MASK;
++ } else if (len >= 7 && is_shift (accelerator)) {
++ accelerator += 7;
++ len -= 7;
++ mods |= IBUS_SHIFT_MASK;
++ } else if (len >= 6 && is_shft (accelerator)) {
++ accelerator += 6;
++ len -= 6;
++ mods |= IBUS_SHIFT_MASK;
++ } else if (len >= 6 && is_ctrl (accelerator)) {
++ accelerator += 6;
++ len -= 6;
++ mods |= IBUS_CONTROL_MASK;
++ } else if (len >= 6 && is_modx (accelerator)) {
++ static const guint mod_vals[] = {
++ IBUS_MOD1_MASK, IBUS_MOD2_MASK, IBUS_MOD3_MASK,
++ IBUS_MOD4_MASK, IBUS_MOD5_MASK
++ };
++
++ len -= 6;
++ accelerator += 4;
++ mods |= mod_vals[*accelerator - '1'];
++ accelerator += 2;
++ } else if (len >= 5 && is_ctl (accelerator)) {
++ accelerator += 5;
++ len -= 5;
++ mods |= IBUS_CONTROL_MASK;
++ } else if (len >= 5 && is_alt (accelerator)) {
++ accelerator += 5;
++ len -= 5;
++ mods |= IBUS_MOD1_MASK;
++ } else if (len >= 6 && is_meta (accelerator)) {
++ accelerator += 6;
++ len -= 6;
++ mods |= IBUS_META_MASK;
++ } else if (len >= 7 && is_hyper (accelerator)) {
++ accelerator += 7;
++ len -= 7;
++ mods |= IBUS_HYPER_MASK;
++ } else if (len >= 7 && is_super (accelerator)) {
++ accelerator += 7;
++ len -= 7;
++ mods |= IBUS_SUPER_MASK;
++ } else {
++ gchar last_ch;
++
++ last_ch = *accelerator;
++ while (last_ch && last_ch != '>') {
++ last_ch = *accelerator;
++ accelerator += 1;
++ len -= 1;
++ }
++ }
++ } else {
++ if (len >= 4 && is_keycode (accelerator)) {
++ /* There was a keycode in the string, but
++ * we cannot store it, so we have an error */
++ error = TRUE;
++ goto out;
++ } else {
++ keyval = ibus_keyval_from_name (accelerator);
++ if (keyval == IBUS_KEY_VoidSymbol) {
++ error = TRUE;
++ goto out;
++ }
++ }
++
++ accelerator += len;
++ len -= len;
++ }
++ }
++
++out:
++ if (error)
++ keyval = mods = 0;
++
++ if (accelerator_key)
++ *accelerator_key = ibus_keyval_to_lower (keyval);
++ if (accelerator_mods)
++ *accelerator_mods = mods;
++}
++
++/**
++ * ibus_accelerator_name:
++ * @accelerator_key: accelerator keyval
++ * @accelerator_mods: accelerator modifier mask
++ *
++ * Converts an accelerator keyval and modifier mask into a string
++ * parseable by gtk_accelerator_parse(). For example, if you pass in
++ * #IBUS_KEY_q and #IBUS_CONTROL_MASK, this function returns “<Control>q”.
++ *
++ * If you need to display accelerators in the user interface,
++ * see gtk_accelerator_get_label().
++ *
++ * Returns: a newly-allocated accelerator name
++ */
++gchar*
++ibus_accelerator_name (guint accelerator_key,
++ IBusModifierType accelerator_mods)
++{
++ static const gchar text_release[] = "<Release>";
++ static const gchar text_primary[] = "<Primary>";
++ static const gchar text_shift[] = "<Shift>";
++ static const gchar text_control[] = "<Control>";
++ static const gchar text_mod1[] = "<Alt>";
++ static const gchar text_mod2[] = "<Mod2>";
++ static const gchar text_mod3[] = "<Mod3>";
++ static const gchar text_mod4[] = "<Mod4>";
++ static const gchar text_mod5[] = "<Mod5>";
++ static const gchar text_meta[] = "<Meta>";
++ static const gchar text_super[] = "<Super>";
++ static const gchar text_hyper[] = "<Hyper>";
++ IBusModifierType saved_mods;
++ guint l;
++ const gchar *keyval_name;
++ gchar *accelerator;
++
++ accelerator_mods &= IBUS_MODIFIER_MASK;
++
++ keyval_name = ibus_keyval_name (ibus_keyval_to_lower (accelerator_key));
++ if (!keyval_name)
++ keyval_name = "";
++
++ saved_mods = accelerator_mods;
++ l = 0;
++ if (accelerator_mods & IBUS_RELEASE_MASK)
++ l += sizeof (text_release) - 1;
++ if (accelerator_mods & _IBUS_GET_PRIMARY_ACCEL_MOD) {
++ l += sizeof (text_primary) - 1;
++ /* consume the default accel */
++ accelerator_mods &= ~_IBUS_GET_PRIMARY_ACCEL_MOD;
++ }
++ if (accelerator_mods & IBUS_SHIFT_MASK)
++ l += sizeof (text_shift) - 1;
++ if (accelerator_mods & IBUS_CONTROL_MASK)
++ l += sizeof (text_control) - 1;
++ if (accelerator_mods & IBUS_MOD1_MASK)
++ l += sizeof (text_mod1) - 1;
++ if (accelerator_mods & IBUS_MOD2_MASK)
++ l += sizeof (text_mod2) - 1;
++ if (accelerator_mods & IBUS_MOD3_MASK)
++ l += sizeof (text_mod3) - 1;
++ if (accelerator_mods & IBUS_MOD4_MASK)
++ l += sizeof (text_mod4) - 1;
++ if (accelerator_mods & IBUS_MOD5_MASK)
++ l += sizeof (text_mod5) - 1;
++ l += strlen (keyval_name);
++ if (accelerator_mods & IBUS_META_MASK)
++ l += sizeof (text_meta) - 1;
++ if (accelerator_mods & IBUS_HYPER_MASK)
++ l += sizeof (text_hyper) - 1;
++ if (accelerator_mods & IBUS_SUPER_MASK)
++ l += sizeof (text_super) - 1;
++
++ accelerator = g_new (gchar, l + 1);
++
++ accelerator_mods = saved_mods;
++ l = 0;
++ accelerator[l] = 0;
++ if (accelerator_mods & IBUS_RELEASE_MASK) {
++ strcpy (accelerator + l, text_release);
++ l += sizeof (text_release) - 1;
++ }
++ if (accelerator_mods & _IBUS_GET_PRIMARY_ACCEL_MOD) {
++ strcpy (accelerator + l, text_primary);
++ l += sizeof (text_primary) - 1;
++ /* consume the default accel */
++ accelerator_mods &= ~_IBUS_GET_PRIMARY_ACCEL_MOD;
++ }
++ if (accelerator_mods & IBUS_SHIFT_MASK) {
++ strcpy (accelerator + l, text_shift);
++ l += sizeof (text_shift) - 1;
++ }
++ if (accelerator_mods & IBUS_CONTROL_MASK) {
++ strcpy (accelerator + l, text_control);
++ l += sizeof (text_control) - 1;
++ }
++ if (accelerator_mods & IBUS_MOD1_MASK) {
++ strcpy (accelerator + l, text_mod1);
++ l += sizeof (text_mod1) - 1;
++ }
++ if (accelerator_mods & IBUS_MOD2_MASK) {
++ strcpy (accelerator + l, text_mod2);
++ l += sizeof (text_mod2) - 1;
++ }
++ if (accelerator_mods & IBUS_MOD3_MASK) {
++ strcpy (accelerator + l, text_mod3);
++ l += sizeof (text_mod3) - 1;
++ }
++ if (accelerator_mods & IBUS_MOD4_MASK) {
++ strcpy (accelerator + l, text_mod4);
++ l += sizeof (text_mod4) - 1;
++ }
++ if (accelerator_mods & IBUS_MOD5_MASK) {
++ strcpy (accelerator + l, text_mod5);
++ l += sizeof (text_mod5) - 1;
++ }
++ if (accelerator_mods & IBUS_META_MASK) {
++ strcpy (accelerator + l, text_meta);
++ l += sizeof (text_meta) - 1;
++ }
++ if (accelerator_mods & IBUS_HYPER_MASK) {
++ strcpy (accelerator + l, text_hyper);
++ l += sizeof (text_hyper) - 1;
++ }
++ if (accelerator_mods & IBUS_SUPER_MASK) {
++ strcpy (accelerator + l, text_super);
++ l += sizeof (text_super) - 1;
++ }
++ strcpy (accelerator + l, keyval_name);
++
++ return accelerator;
++}
+diff --git a/src/ibusaccelgroup.h b/src/ibusaccelgroup.h
+new file mode 100644
+index 00000000..cb38bee4
+--- /dev/null
++++ b/src/ibusaccelgroup.h
+@@ -0,0 +1,51 @@
++/* GTK - The GIMP Toolkit
++ * Copyright (C) 1998, 2001 Tim Janik
++ *
++ * 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 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 <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
++ * file for a list of people on the GTK+ Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#ifndef __IBUS_ACCEL_GROUP_H_
++#define __IBUS_ACCEL_GROUP_H_
++
++
++#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION)
++#error "Only <ibus.h> can be included directly"
++#endif
++
++#include <glib.h>
++#include <ibustypes.h>
++
++G_BEGIN_DECLS
++
++
++/* --- Accelerators--- */
++gboolean ibus_accelerator_valid (guint keyval,
++ IBusModifierType modifiers)
++ G_GNUC_CONST;
++void ibus_accelerator_parse (const gchar *accelerator,
++ guint *accelerator_key,
++ IBusModifierType *accelerator_mods);
++gchar* ibus_accelerator_name (guint accelerator_key,
++ IBusModifierType accelerator_mods);
++
++G_END_DECLS
++
++#endif /* __IBUS_ACCEL_GROUP_H_ */
+diff --git a/src/ibusengine.c b/src/ibusengine.c
+index da648d11..9a0b1a8a 100644
+--- a/src/ibusengine.c
++++ b/src/ibusengine.c
+@@ -20,12 +20,16 @@
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+-#include "ibusengine.h"
+ #include <stdarg.h>
+ #include <string.h>
++
++#include "ibusaccelgroup.h"
++#include "ibusengine.h"
++#include "ibuskeysyms.h"
+ #include "ibusmarshalers.h"
+ #include "ibusinternal.h"
+ #include "ibusshare.h"
++#include "ibusxevent.h"
+
+ #define IBUS_ENGINE_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE, IBusEnginePrivate))
+@@ -60,6 +64,8 @@ enum {
+ };
+
+
++typedef struct _IBusEngineKeybinding IBusEngineKeybinding;
++
+ /* IBusEnginePriv */
+ struct _IBusEnginePrivate {
+ gchar *engine_name;
+@@ -74,11 +80,19 @@ struct _IBusEnginePrivate {
+ /* cached content-type */
+ guint content_purpose;
+ guint content_hints;
++
++ GSettings *settings_emoji;
++ IBusEngineKeybinding **emoji_keybindings;
++};
++
++struct _IBusEngineKeybinding {
++ guint keyval;
++ IBusModifierType modifiers;
+ };
+
+ static guint engine_signals[LAST_SIGNAL] = { 0 };
+
+-static IBusText *text_empty = NULL;
++static IBusText *text_empty;
+
+ /* functions prototype */
+ static void ibus_engine_destroy (IBusEngine *engine);
+@@ -176,6 +190,11 @@ static void ibus_engine_dbus_property_changed
+ (IBusEngine *engine,
+ const gchar *property_name,
+ GVariant *value);
++static void ibus_engine_keybinding_free (IBusEngine *engine);
++static void settings_emoji_hotkey_changed_cb
++ (GSettings *settings,
++ const gchar *key,
++ gpointer data);
+
+
+ G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
+@@ -263,11 +282,27 @@ static const gchar introspection_xml[] =
+ " <arg type='u' name='keycode' />"
+ " <arg type='u' name='state' />"
+ " </signal>"
++ " <signal name='PanelExtension'>"
++ " <arg type='v' name='data' />"
++ " </signal>"
+ /* FIXME properties */
+ " <property name='ContentType' type='(uu)' access='write' />"
+ " </interface>"
+ "</node>";
+
++static const guint IBUS_MODIFIER_FILTER =
++ IBUS_MODIFIER_MASK & ~(
++ IBUS_LOCK_MASK | /* Caps Lock */
++ IBUS_MOD2_MASK | /* Num Lock */
++ IBUS_BUTTON1_MASK |
++ IBUS_BUTTON2_MASK |
++ IBUS_BUTTON3_MASK |
++ IBUS_BUTTON4_MASK |
++ IBUS_BUTTON5_MASK |
++ IBUS_SUPER_MASK |
++ IBUS_HYPER_MASK |
++ IBUS_META_MASK);
++
+ static void
+ ibus_engine_class_init (IBusEngineClass *class)
+ {
+@@ -802,9 +837,15 @@ ibus_engine_class_init (IBusEngineClass *class)
+ static void
+ ibus_engine_init (IBusEngine *engine)
+ {
+- engine->priv = IBUS_ENGINE_GET_PRIVATE (engine);
+-
+- engine->priv->surrounding_text = g_object_ref_sink (text_empty);
++ IBusEnginePrivate *priv;
++ engine->priv = priv = IBUS_ENGINE_GET_PRIVATE (engine);
++
++ priv->surrounding_text = g_object_ref_sink (text_empty);
++ priv->settings_emoji =
++ g_settings_new ("org.freedesktop.ibus.panel.emoji");
++ settings_emoji_hotkey_changed_cb (priv->settings_emoji, "hotkey", engine);
++ g_signal_connect (priv->settings_emoji, "changed::hotkey",
++ G_CALLBACK (settings_emoji_hotkey_changed_cb), engine);
+ }
+
+ static void
+@@ -817,6 +858,7 @@ ibus_engine_destroy (IBusEngine *engine)
+ g_object_unref (engine->priv->surrounding_text);
+ engine->priv->surrounding_text = NULL;
+ }
++ ibus_engine_keybinding_free (engine);
+
+ IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
+ }
+@@ -852,6 +894,53 @@ ibus_engine_get_property (IBusEngine *engine,
+ }
+ }
+
++static void
++ibus_engine_panel_extension (IBusEngine *engine)
++{
++ IBusXEvent *xevent = ibus_x_event_new (
++ "event-type", IBUS_X_EVENT_KEY_PRESS,
++ "purpose", "emoji",
++ NULL);
++ GVariant *data = ibus_serializable_serialize_object (
++ IBUS_SERIALIZABLE (xevent));
++
++ g_assert (data != NULL);
++ ibus_engine_emit_signal (engine,
++ "PanelExtension",
++ g_variant_new ("(v)", data));
++}
++
++static gboolean
++ibus_engine_filter_key_event (IBusEngine *engine,
++ guint keyval,
++ guint keycode,
++ guint state)
++{
++ IBusEnginePrivate *priv;
++ int i;
++ guint modifiers;
++
++ if ((state & IBUS_RELEASE_MASK) != 0)
++ return FALSE;
++ g_return_val_if_fail (IBUS_IS_ENGINE (engine), FALSE);
++
++ priv = engine->priv;
++ modifiers = state & IBUS_MODIFIER_FILTER;
++ if (keyval >= IBUS_KEY_A && keyval <= IBUS_KEY_Z &&
++ (modifiers & IBUS_SHIFT_MASK) != 0) {
++ keyval = keyval - IBUS_KEY_A + IBUS_KEY_a;
++ }
++ for (i = 0; priv->emoji_keybindings[i]; i++) {
++ IBusEngineKeybinding *binding = priv->emoji_keybindings[i];
++ if (binding->keyval == keyval &&
++ binding->modifiers == modifiers) {
++ ibus_engine_panel_extension (engine);
++ return TRUE;
++ }
++ }
++ return FALSE;
++}
++
+ static gboolean
+ ibus_engine_service_authorized_method (IBusService *service,
+ GDBusConnection *connection)
+@@ -892,6 +981,7 @@ ibus_engine_service_method_call (IBusService *service,
+ if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) {
+ guint keyval, keycode, state;
+ gboolean retval = FALSE;
++
+ g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state);
+ g_signal_emit (engine,
+ engine_signals[PROCESS_KEY_EVENT],
+@@ -900,6 +990,12 @@ ibus_engine_service_method_call (IBusService *service,
+ keycode,
+ state,
+ &retval);
++ if (!retval) {
++ retval = ibus_engine_filter_key_event (engine,
++ keyval,
++ keycode,
++ state);
++ }
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval));
+ return;
+ }
+@@ -1338,6 +1434,79 @@ ibus_engine_dbus_property_changed (IBusEngine *engine,
+ g_object_unref (message);
+ }
+
++static void
++ibus_engine_keybinding_free (IBusEngine *engine)
++{
++ IBusEnginePrivate *priv;
++ int i;
++
++ g_return_if_fail (IBUS_IS_ENGINE (engine));
++
++ priv = engine->priv;
++ if (priv->emoji_keybindings) {
++ for (i = 0; priv->emoji_keybindings[i]; i++)
++ g_slice_free (IBusEngineKeybinding, priv->emoji_keybindings[i]);
++ g_clear_pointer (&priv->emoji_keybindings, g_free);
++ }
++}
++
++static IBusEngineKeybinding *
++ibus_engine_keybinding_new (IBusEngine *engine,
++ const gchar *accelerator)
++{
++ guint keyval = 0U;
++ IBusModifierType modifiers = 0;
++ IBusEngineKeybinding *binding = NULL;
++
++ ibus_accelerator_parse (accelerator, &keyval, &modifiers);
++ if (keyval == 0U && modifiers == 0) {
++ g_warning ("Failed to parse shortcut key '%s'", accelerator);
++ return NULL;
++ }
++ if (modifiers & IBUS_SUPER_MASK) {
++ modifiers^=IBUS_SUPER_MASK;
++ modifiers|=IBUS_MOD4_MASK;
++ }
++
++ binding = g_slice_new0 (IBusEngineKeybinding);
++ binding->keyval = keyval;
++ binding->modifiers = modifiers;
++ return binding;
++}
++
++static void
++settings_emoji_hotkey_changed_cb (GSettings *settings,
++ const gchar *key,
++ gpointer data)
++{
++ IBusEngine *engine;
++ IBusEnginePrivate *priv;
++ gchar **accelerators;
++ int i, j, length;
++ g_return_if_fail (IBUS_IS_ENGINE (data));
++ engine = IBUS_ENGINE (data);
++ priv = engine->priv;
++
++ if (g_strcmp0 (key, "hotkey") != 0)
++ return;
++ accelerators = g_settings_get_strv (settings, key);
++ length = g_strv_length (accelerators);
++ ibus_engine_keybinding_free (engine);
++ if (length == 0) {
++ g_strfreev (accelerators);
++ return;
++ }
++ priv->emoji_keybindings = g_new0 (IBusEngineKeybinding*, length + 1);
++ for (i = 0, j = 0; i < length; i++) {
++ IBusEngineKeybinding *binding =
++ ibus_engine_keybinding_new (engine, accelerators[i]);
++ if (!binding)
++ continue;
++ priv->emoji_keybindings[j++] = binding;
++ }
++ g_strfreev (accelerators);
++}
++
+ IBusEngine *
+ ibus_engine_new (const gchar *engine_name,
+ const gchar *object_path,
+diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
+index c85dfa86..8217a000 100644
+--- a/ui/gtk3/emojier.vala
++++ b/ui/gtk3/emojier.vala
+@@ -2062,6 +2062,7 @@ public class IBusEmojier : Gtk.ApplicationWindow {
+ // Do not hide a bottom panel in XFCE4
+ if (work_area.y < y)
+ y = work_area.y;
++ // FIXME: move() does not work in Wayland
+ move(x, y);
+
+ uint32 timestamp = event.get_time();
+diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala
+index a170280b..03026d00 100644
+--- a/ui/gtk3/extension.vala
++++ b/ui/gtk3/extension.vala
+@@ -115,8 +115,9 @@ class ExtensionGtk {
+ // and Ctrl-Shift-e when ibus-ui-gtk3 runs after the
+ // desktop is launched.
+ GLib.Environment.unset_variable("GDK_CORE_DEVICE_EVENTS");
+- // for Gdk.X11.get_default_xdisplay()
+- Gdk.set_allowed_backends("x11");
++ // Gdk.set_allowed_backends("x11") let present_with_time() failed on
++ // launching the dialog secondly in Wayland.
++ //Gdk.set_allowed_backends("x11");
+
+ ExtensionGtk extension = new ExtensionGtk(argv);
+ extension.run();
+diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala
+index 1fbf6cfc..e3f39e12 100644
+--- a/ui/gtk3/panelbinding.vala
++++ b/ui/gtk3/panelbinding.vala
+@@ -33,8 +33,6 @@ class PanelBinding : IBus.PanelService {
+ private string[] m_emojier_favorites = {};
+ private Gtk.CssProvider m_css_provider;
+ private const uint PRELOAD_ENGINES_DELAY_TIME = 30000;
+- private GLib.List<BindingCommon.Keybinding> m_keybindings =
+- new GLib.List<BindingCommon.Keybinding>();
+ private bool m_load_emoji_at_startup;
+ private bool m_loaded_emoji = false;
+ private bool m_load_unicode_at_startup;
+@@ -49,15 +47,6 @@ class PanelBinding : IBus.PanelService {
+ m_bus = bus;
+
+ init_settings();
+-
+- bind_emoji_shortcut();
+- }
+-
+-
+- ~PanelBinding() {
+- BindingCommon.unbind_switch_shortcut(
+- BindingCommon.KeyEventFuncType.ANY,
+- m_keybindings);
+ }
+
+
+@@ -77,13 +66,6 @@ class PanelBinding : IBus.PanelService {
+ ref m_css_provider);
+ });
+
+- m_settings_emoji.changed["hotkey"].connect((key) => {
+- BindingCommon.unbind_switch_shortcut(
+- BindingCommon.KeyEventFuncType.EMOJI_TYPING,
+- m_keybindings);
+- bind_emoji_shortcut();
+- });
+-
+ m_settings_emoji.changed["font"].connect((key) => {
+ BindingCommon.set_custom_font(m_settings_panel,
+ m_settings_emoji,
+@@ -124,25 +106,6 @@ class PanelBinding : IBus.PanelService {
+ }
+
+
+- private void bind_emoji_shortcut() {
+-#if EMOJI_DICT
+- string[] accelerators = m_settings_emoji.get_strv("hotkey");
+-
+- var keybinding_manager = KeybindingManager.get_instance();
+-
+- foreach (var accelerator in accelerators) {
+- BindingCommon.keybinding_manager_bind(
+- keybinding_manager,
+- ref m_keybindings,
+- accelerator,
+- BindingCommon.KeyEventFuncType.EMOJI_TYPING,
+- handle_emoji_typing,
+- null);
+- }
+-#endif
+- }
+-
+-
+ private void set_emoji_favorites() {
+ m_emojier_favorites = m_settings_emoji.get_strv("favorites");
+ IBusEmojier.set_favorites(
+@@ -195,9 +158,6 @@ class PanelBinding : IBus.PanelService {
+
+ set_load_emoji_at_startup();
+ set_load_unicode_at_startup();
+- BindingCommon.unbind_switch_shortcut(BindingCommon.KeyEventFuncType.ANY,
+- m_keybindings);
+- bind_emoji_shortcut();
+ BindingCommon.set_custom_font(m_settings_panel,
+ m_settings_emoji,
+ ref m_css_provider);
+@@ -354,19 +314,26 @@ class PanelBinding : IBus.PanelService {
+ return;
+ }
+ Gdk.Event event = new Gdk.Event(event_type);
+- event.key.time = xevent.get_time();
+- Gdk.Display? display = Gdk.Display.get_default();
++ uint32 time = xevent.get_time();
++ if (time == 0)
++ time = Gtk.get_current_event_time();
++ event.key.time = time;
+ X.Window xid = xevent.get_window();
+- Gdk.X11.Window window;
+- window = Gdk.X11.Window.lookup_for_display(
+- display as Gdk.X11.Display, xid);
+- if (window != null) {
+- event.key.window = window;
+- } else {
++ Gdk.Display? display = Gdk.Display.get_default();
++ Gdk.Window? window = null;
++ if (window == null && xid != 0) {
++ window = Gdk.X11.Window.lookup_for_display(
++ display as Gdk.X11.Display, xid);
++ }
++ if (window == null && xid != 0) {
+ window = new Gdk.X11.Window.foreign_for_display(
+ display as Gdk.X11.Display, xid);
+- event.key.window = window;
+ }
++ if (window == null) {
++ window = Gdk.get_default_root_window();
++ window.ref();
++ }
++ event.key.window = window;
+ handle_emoji_typing(event);
+ }
+ }
+--
+2.14.3
+
diff --git a/ibus.spec b/ibus.spec
index 455a95d..d28d46d 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -30,7 +30,7 @@
Name: ibus
Version: 1.5.17
-Release: 9%{?dist}
+Release: 10%{?dist}
Summary: Intelligent Input Bus for Linux OS
License: LGPLv2+
Group: System Environment/Libraries
@@ -424,6 +424,10 @@ dconf update || :
%{_datadir}/gtk-doc/html/*
%changelog
+* Tue Feb 27 2018 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.17-10
+- Disabled panel extension for gdm user
+- Enabled panel extension in Wayland
+
* Wed Feb 21 2018 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.17-9
- Added panel extension for emoji keybinding not to depen on desktops
- Showed Unicode code points on Unicode name list
reply other threads:[~2026-05-31 2:06 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178019320656.1.9013830562427065902.rpms-ibus-cf670af51697@fedoraproject.org \
--to=tfujiwar@redhat.com \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox