public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ibus] autotool: Enabled panel extension in Wayland
@ 2026-05-31  2:06 Takao Fujiwara
  0 siblings, 0 replies; only message in thread
From: Takao Fujiwara @ 2026-05-31  2:06 UTC (permalink / raw)
  To: git-commits

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

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-05-31  2:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-31  2:06 [rpms/ibus] autotool: Enabled panel extension in Wayland Takao Fujiwara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox