Blame src/ibushotkey.c

Packit Service 1d8f1c
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit Service 1d8f1c
/* vim:set et sts=4: */
Packit Service 1d8f1c
/* IBus - The Input Bus
Packit Service 1d8f1c
 * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2008-2018 Red Hat, Inc.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is free software; you can redistribute it and/or
Packit Service 1d8f1c
 * modify it under the terms of the GNU Lesser General Public
Packit Service 1d8f1c
 * License as published by the Free Software Foundation; either
Packit Service 1d8f1c
 * version 2.1 of the License, or (at your option) any later version.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is distributed in the hope that it will be useful,
Packit Service 1d8f1c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 1d8f1c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 1d8f1c
 * Lesser General Public License for more details.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * You should have received a copy of the GNU Lesser General Public
Packit Service 1d8f1c
 * License along with this library; if not, write to the Free Software
Packit Service 1d8f1c
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
Packit Service 1d8f1c
 * USA
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
#include "ibushotkey.h"
Packit Service 1d8f1c
#include "ibusmarshalers.h"
Packit Service 1d8f1c
#include "ibuskeysyms.h"
Packit Service 1d8f1c
#include "ibusinternal.h"
Packit Service 1d8f1c
#include "ibusshare.h"
Packit Service 1d8f1c
Packit Service 1d8f1c
#define IBUS_HOTKEY_PROFILE_GET_PRIVATE(o)  \
Packit Service 1d8f1c
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_HOTKEY_PROFILE, IBusHotkeyProfilePrivate))
Packit Service 1d8f1c
Packit Service 1d8f1c
enum {
Packit Service 1d8f1c
    TRIGGER,
Packit Service 1d8f1c
    LAST_SIGNAL,
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
typedef struct _IBusHotkey IBusHotkey;
Packit Service 1d8f1c
typedef struct _IBusHotkeyEvent IBusHotkeyEvent;
Packit Service 1d8f1c
typedef struct _IBusHotkeyProfilePrivate IBusHotkeyProfilePrivate;
Packit Service 1d8f1c
Packit Service 1d8f1c
struct _IBusHotkey {
Packit Service 1d8f1c
    guint   keyval;
Packit Service 1d8f1c
    guint   modifiers;
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
struct _IBusHotkeyEvent {
Packit Service 1d8f1c
    GQuark event;
Packit Service 1d8f1c
    GList *hotkeys;
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
struct _IBusHotkeyProfilePrivate {
Packit Service 1d8f1c
    GTree *hotkeys;
Packit Service 1d8f1c
    GArray *events;
Packit Service 1d8f1c
    guint   mask;
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
/* functions prototype */
Packit Service 1d8f1c
static IBusHotkey   *ibus_hotkey_new                (guint                   keyval,
Packit Service 1d8f1c
                                                     guint                   modifiers);
Packit Service 1d8f1c
static IBusHotkey   *ibus_hotkey_copy               (const IBusHotkey       *src);
Packit Service 1d8f1c
static void          ibus_hotkey_free               (IBusHotkey             *hotkey);
Packit Service 1d8f1c
static void          ibus_hotkey_profile_class_init (IBusHotkeyProfileClass *class);
Packit Service 1d8f1c
static void          ibus_hotkey_profile_init       (IBusHotkeyProfile      *profile);
Packit Service 1d8f1c
static void          ibus_hotkey_profile_destroy    (IBusHotkeyProfile      *profile);
Packit Service 1d8f1c
static gboolean      ibus_hotkey_profile_serialize  (IBusHotkeyProfile      *profile,
Packit Service 1d8f1c
                                                     GVariantBuilder        *builder);
Packit Service 1d8f1c
static gint          ibus_hotkey_profile_deserialize(IBusHotkeyProfile      *profile,
Packit Service 1d8f1c
                                                     GVariant               *variant);
Packit Service 1d8f1c
static gboolean      ibus_hotkey_profile_copy       (IBusHotkeyProfile      *dest,
Packit Service 1d8f1c
                                                     const IBusHotkeyProfile*src);
Packit Service 1d8f1c
static void          ibus_hotkey_profile_trigger    (IBusHotkeyProfile      *profile,
Packit Service 1d8f1c
                                                     GQuark                  event,
Packit Service 1d8f1c
                                                     gpointer                user_data);
Packit Service 1d8f1c
Packit Service 1d8f1c
// Normalize modifiers by setting necessary modifier bits according to keyval.
Packit Service 1d8f1c
static guint         normalize_modifiers            (guint                   keyval,
Packit Service 1d8f1c
                                                     guint                   modifiers);
Packit Service 1d8f1c
static gboolean      is_modifier                    (guint                   keyval);
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusSerializableClass *parent_class = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
static guint profile_signals[LAST_SIGNAL] = { 0 };
Packit Service 1d8f1c
Packit Service 1d8f1c
GType
Packit Service 1d8f1c
ibus_hotkey_get_type (void)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    static GType type = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (type == 0) {
Packit Service 1d8f1c
        type = g_boxed_type_register_static ("IBusHotkey",
Packit Service 1d8f1c
                                             (GBoxedCopyFunc) ibus_hotkey_copy,
Packit Service 1d8f1c
                                             (GBoxedFreeFunc) ibus_hotkey_free);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return type;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusHotkey *
Packit Service 1d8f1c
ibus_hotkey_new (guint keyval,
Packit Service 1d8f1c
                 guint modifiers)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkey *hotkey = g_slice_new (IBusHotkey);
Packit Service 1d8f1c
Packit Service 1d8f1c
    hotkey->keyval = keyval;
Packit Service 1d8f1c
    hotkey->modifiers = modifiers;
Packit Service 1d8f1c
Packit Service 1d8f1c
    return hotkey;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_hotkey_free (IBusHotkey *hotkey)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_slice_free (IBusHotkey, hotkey);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusHotkey *
Packit Service 1d8f1c
ibus_hotkey_copy (const IBusHotkey *src)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    return ibus_hotkey_new (src->keyval, src->modifiers);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gint
Packit Service 1d8f1c
ibus_hotkey_cmp_with_data (IBusHotkey *hotkey1,
Packit Service 1d8f1c
                           IBusHotkey *hotkey2,
Packit Service 1d8f1c
                           gpointer    user_data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gint retval;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (hotkey1 == hotkey2)
Packit Service 1d8f1c
        return 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = hotkey1->keyval - hotkey2->keyval;
Packit Service 1d8f1c
    if (retval == 0)
Packit Service 1d8f1c
        retval = hotkey1->modifiers - hotkey2->modifiers;
Packit Service 1d8f1c
Packit Service 1d8f1c
    return retval;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
GType
Packit Service 1d8f1c
ibus_hotkey_profile_get_type (void)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    static GType type = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    static const GTypeInfo type_info = {
Packit Service 1d8f1c
        sizeof (IBusHotkeyProfileClass),
Packit Service 1d8f1c
        (GBaseInitFunc)     NULL,
Packit Service 1d8f1c
        (GBaseFinalizeFunc) NULL,
Packit Service 1d8f1c
        (GClassInitFunc)    ibus_hotkey_profile_class_init,
Packit Service 1d8f1c
        NULL,               /* class finialize */
Packit Service 1d8f1c
        NULL,               /* class data */
Packit Service 1d8f1c
        sizeof (IBusHotkeyProfile),
Packit Service 1d8f1c
        0,
Packit Service 1d8f1c
        (GInstanceInitFunc) ibus_hotkey_profile_init,
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (type == 0) {
Packit Service 1d8f1c
        type = g_type_register_static (IBUS_TYPE_SERIALIZABLE,
Packit Service 1d8f1c
                                       "IBusHotkeyProfile",
Packit Service 1d8f1c
                                       &type_info,
Packit Service 1d8f1c
                                       0);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return type;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_hotkey_profile_class_init (IBusHotkeyProfileClass *class)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
Packit Service 1d8f1c
    IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class);
Packit Service 1d8f1c
Packit Service 1d8f1c
    parent_class = (IBusSerializableClass *) g_type_class_peek_parent (class);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_type_class_add_private (class, sizeof (IBusHotkeyProfilePrivate));
Packit Service 1d8f1c
Packit Service 1d8f1c
    object_class->destroy = (IBusObjectDestroyFunc) ibus_hotkey_profile_destroy;
Packit Service 1d8f1c
Packit Service 1d8f1c
    serializable_class->serialize   = (IBusSerializableSerializeFunc) ibus_hotkey_profile_serialize;
Packit Service 1d8f1c
    serializable_class->deserialize = (IBusSerializableDeserializeFunc) ibus_hotkey_profile_deserialize;
Packit Service 1d8f1c
    serializable_class->copy        = (IBusSerializableCopyFunc) ibus_hotkey_profile_copy;
Packit Service 1d8f1c
Packit Service 1d8f1c
    class->trigger = ibus_hotkey_profile_trigger;
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* install signals */
Packit Service 1d8f1c
    /**
Packit Service 1d8f1c
     * IBusHotkeyProfile::trigger:
Packit Service 1d8f1c
     * @profile: An IBusHotkeyProfile.
Packit Service 1d8f1c
     * @event: An event in GQuark.
Packit Service 1d8f1c
     * @user_data: User data for callback.
Packit Service 1d8f1c
     *
Packit Service 1d8f1c
     * Emitted when a hotkey is pressed and the hotkey is in profile.
Packit Service 1d8f1c
     * Implement the member function trigger() in extended class to receive this signal.
Packit Service 1d8f1c
     *
Packit Service 1d8f1c
     * <note><para>The last parameter, user_data is not actually a valid parameter. It is displayed because of GtkDoc bug.</para></note>
Packit Service 1d8f1c
     */
Packit Service 1d8f1c
    profile_signals[TRIGGER] =
Packit Service 1d8f1c
        g_signal_new (I_("trigger"),
Packit Service 1d8f1c
            G_TYPE_FROM_CLASS (class),
Packit Service 1d8f1c
            G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
Packit Service 1d8f1c
            G_STRUCT_OFFSET (IBusHotkeyProfileClass, trigger),
Packit Service 1d8f1c
            NULL, NULL,
Packit Service 1d8f1c
            _ibus_marshal_VOID__UINT_POINTER,
Packit Service 1d8f1c
            G_TYPE_NONE,
Packit Service 1d8f1c
            2,
Packit Service 1d8f1c
            G_TYPE_UINT,
Packit Service 1d8f1c
            G_TYPE_POINTER);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_hotkey_profile_init (IBusHotkeyProfile *profile)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    priv->hotkeys = g_tree_new_full ((GCompareDataFunc) ibus_hotkey_cmp_with_data,
Packit Service 1d8f1c
                                     NULL,
Packit Service 1d8f1c
                                     (GDestroyNotify) ibus_hotkey_free,
Packit Service 1d8f1c
                                     NULL);
Packit Service 1d8f1c
    priv->events = g_array_new (TRUE, TRUE, sizeof (IBusHotkeyEvent));
Packit Service 1d8f1c
Packit Service 1d8f1c
    priv->mask = IBUS_SHIFT_MASK |
Packit Service 1d8f1c
                 IBUS_CONTROL_MASK |
Packit Service 1d8f1c
                 IBUS_MOD1_MASK |
Packit Service 1d8f1c
                 IBUS_SUPER_MASK |
Packit Service 1d8f1c
                 IBUS_HYPER_MASK |
Packit Service 1d8f1c
                 IBUS_RELEASE_MASK;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_hotkey_profile_destroy (IBusHotkeyProfile *profile)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* free events */
Packit Service 1d8f1c
    if (priv->events) {
Packit Service 1d8f1c
        IBusHotkeyEvent *p;
Packit Service 1d8f1c
        gint i;
Packit Service 1d8f1c
        p = (IBusHotkeyEvent *)g_array_free (priv->events, FALSE);
Packit Service 1d8f1c
        priv->events = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (i = 0; p[i].event != 0; i++) {
Packit Service 1d8f1c
            g_list_free (p[i].hotkeys);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        g_free (p);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (priv->hotkeys) {
Packit Service 1d8f1c
        g_tree_destroy (priv->hotkeys);
Packit Service 1d8f1c
        priv->hotkeys = NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBUS_OBJECT_CLASS (parent_class)->destroy ((IBusObject *)profile);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
ibus_hotkey_profile_serialize (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                               GVariantBuilder   *builder)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gboolean retval;
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = parent_class->serialize ((IBusSerializable *) profile, builder);
Packit Service 1d8f1c
    g_return_val_if_fail (retval, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gint
Packit Service 1d8f1c
ibus_hotkey_profile_deserialize (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                 GVariant          *variant)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gint retval;
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = parent_class->deserialize ((IBusSerializable *) profile, variant);
Packit Service 1d8f1c
    g_return_val_if_fail (retval, 0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return retval;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
ibus_hotkey_profile_copy (IBusHotkeyProfile       *dest,
Packit Service 1d8f1c
                          const IBusHotkeyProfile *src)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gboolean retval;
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = parent_class->copy ((IBusSerializable *)dest,
Packit Service 1d8f1c
                                 (IBusSerializable *)src);
Packit Service 1d8f1c
    g_return_val_if_fail (retval, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (IBUS_IS_HOTKEY_PROFILE (dest), FALSE);
Packit Service 1d8f1c
    g_return_val_if_fail (IBUS_IS_HOTKEY_PROFILE (src), FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
IBusHotkeyProfile *
Packit Service 1d8f1c
ibus_hotkey_profile_new (void)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfile *profile = g_object_new (IBUS_TYPE_HOTKEY_PROFILE, NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return profile;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_hotkey_profile_trigger (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                             GQuark             event,
Packit Service 1d8f1c
                             gpointer           user_data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    // g_debug ("%s is triggerred", g_quark_to_string (event));
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static guint
Packit Service 1d8f1c
normalize_modifiers (guint keyval,
Packit Service 1d8f1c
                     guint modifiers)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    switch(keyval) {
Packit Service 1d8f1c
    case IBUS_KEY_Control_L:
Packit Service 1d8f1c
    case IBUS_KEY_Control_R:
Packit Service 1d8f1c
        return modifiers | IBUS_CONTROL_MASK;
Packit Service 1d8f1c
    case IBUS_KEY_Shift_L:
Packit Service 1d8f1c
    case IBUS_KEY_Shift_R:
Packit Service 1d8f1c
        return modifiers | IBUS_SHIFT_MASK;
Packit Service 1d8f1c
    case IBUS_KEY_Alt_L:
Packit Service 1d8f1c
    case IBUS_KEY_Alt_R:
Packit Service 1d8f1c
    // Chrome OS does not have Meta key. Instead, shift+alt generates Meta keyval.
Packit Service 1d8f1c
    case IBUS_KEY_Meta_L:
Packit Service 1d8f1c
    case IBUS_KEY_Meta_R:
Packit Service 1d8f1c
        return modifiers | IBUS_MOD1_MASK;
Packit Service 1d8f1c
    case IBUS_KEY_Super_L:
Packit Service 1d8f1c
    case IBUS_KEY_Super_R:
Packit Service 1d8f1c
        return modifiers | IBUS_SUPER_MASK;
Packit Service 1d8f1c
    case IBUS_KEY_Hyper_L:
Packit Service 1d8f1c
    case IBUS_KEY_Hyper_R:
Packit Service 1d8f1c
        return modifiers | IBUS_HYPER_MASK;
Packit Service 1d8f1c
    default:
Packit Service 1d8f1c
        return modifiers;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
is_modifier (guint keyval)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    switch(keyval) {
Packit Service 1d8f1c
    case IBUS_KEY_Control_L:
Packit Service 1d8f1c
    case IBUS_KEY_Control_R:
Packit Service 1d8f1c
    case IBUS_KEY_Shift_L:
Packit Service 1d8f1c
    case IBUS_KEY_Shift_R:
Packit Service 1d8f1c
    case IBUS_KEY_Alt_L:
Packit Service 1d8f1c
    case IBUS_KEY_Alt_R:
Packit Service 1d8f1c
    case IBUS_KEY_Meta_L:
Packit Service 1d8f1c
    case IBUS_KEY_Meta_R:
Packit Service 1d8f1c
    case IBUS_KEY_Super_L:
Packit Service 1d8f1c
    case IBUS_KEY_Super_R:
Packit Service 1d8f1c
    case IBUS_KEY_Hyper_L:
Packit Service 1d8f1c
    case IBUS_KEY_Hyper_R:
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    default:
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
gboolean
Packit Service 1d8f1c
ibus_hotkey_profile_add_hotkey (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                guint              keyval,
Packit Service 1d8f1c
                                guint              modifiers,
Packit Service 1d8f1c
                                GQuark             event)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBusHotkey *hotkey = ibus_hotkey_new (keyval,
Packit Service 1d8f1c
                                          normalize_modifiers (keyval, modifiers & priv->mask));
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* has the same hotkey in profile */
Packit Service 1d8f1c
    if (g_tree_lookup (priv->hotkeys, hotkey) != NULL) {
Packit Service 1d8f1c
        ibus_hotkey_free (hotkey);
Packit Service 1d8f1c
        g_return_val_if_reached (FALSE);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_tree_insert (priv->hotkeys, (gpointer) hotkey, GUINT_TO_POINTER (event));
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBusHotkeyEvent *p = NULL;
Packit Service 1d8f1c
    gint i;
Packit Service 1d8f1c
    for ( i = 0; i < priv->events->len; i++) {
Packit Service 1d8f1c
        p = &g_array_index (priv->events, IBusHotkeyEvent, i);
Packit Service 1d8f1c
        if (p->event == event)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (i >= priv->events->len) {
Packit Service 1d8f1c
        g_array_set_size (priv->events, i + 1);
Packit Service 1d8f1c
        p = &g_array_index (priv->events, IBusHotkeyEvent, i);
Packit Service 1d8f1c
        p->event = event;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    p->hotkeys = g_list_append (p->hotkeys, hotkey);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
gboolean
Packit Service 1d8f1c
ibus_hotkey_profile_add_hotkey_from_string (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                            const gchar       *str,
Packit Service 1d8f1c
                                            GQuark             event)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    guint keyval;
Packit Service 1d8f1c
    guint modifiers;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (ibus_key_event_from_string (str, &keyval, &modifiers) == FALSE) {
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return ibus_hotkey_profile_add_hotkey (profile, keyval, modifiers, event);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
gboolean
Packit Service 1d8f1c
ibus_hotkey_profile_remove_hotkey (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                   guint              keyval,
Packit Service 1d8f1c
                                   guint              modifiers)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    modifiers = normalize_modifiers (keyval, modifiers & priv->mask);
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBusHotkey hotkey = {
Packit Service 1d8f1c
        .keyval = keyval,
Packit Service 1d8f1c
        .modifiers = modifiers
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBusHotkey *p1;
Packit Service 1d8f1c
    GQuark event;
Packit Service 1d8f1c
    gboolean retval;
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = g_tree_lookup_extended (priv->hotkeys,
Packit Service 1d8f1c
                                     &hotkey,
Packit Service 1d8f1c
                                     (gpointer)&p1,
Packit Service 1d8f1c
                                     (gpointer)&event);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!retval)
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
Packit Service 1d8f1c
    gint i;
Packit Service 1d8f1c
    IBusHotkeyEvent *p2 = NULL;
Packit Service 1d8f1c
    for ( i = 0; i < priv->events->len; i++) {
Packit Service 1d8f1c
        p2 = &g_array_index (priv->events, IBusHotkeyEvent, i);
Packit Service 1d8f1c
        if (p2->event == event)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_assert (p2 && p2->event == event);
Packit Service 1d8f1c
Packit Service 1d8f1c
    p2->hotkeys = g_list_remove (p2->hotkeys, p1);
Packit Service 1d8f1c
    if (p2->hotkeys == NULL) {
Packit Service 1d8f1c
        g_array_remove_index_fast (priv->events, i);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_tree_remove (priv->hotkeys, p1);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
gboolean
Packit Service 1d8f1c
ibus_hotkey_profile_remove_hotkey_by_event (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                            GQuark             event)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    gint i;
Packit Service 1d8f1c
    IBusHotkeyEvent *p = NULL;
Packit Service 1d8f1c
    for ( i = 0; i < priv->events->len; i++) {
Packit Service 1d8f1c
        p = &g_array_index (priv->events, IBusHotkeyEvent, i);
Packit Service 1d8f1c
        if (p->event == event)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (p == NULL || p->event != event)
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
Packit Service 1d8f1c
    GList *list;
Packit Service 1d8f1c
    for (list = p->hotkeys; list != NULL; list = list->next) {
Packit Service 1d8f1c
        g_tree_remove (priv->hotkeys, (IBusHotkey *)list->data);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_list_free (p->hotkeys);
Packit Service 1d8f1c
    g_array_remove_index_fast (priv->events, i);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
GQuark
Packit Service 1d8f1c
ibus_hotkey_profile_filter_key_event (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                      guint              keyval,
Packit Service 1d8f1c
                                      guint              modifiers,
Packit Service 1d8f1c
                                      guint              prev_keyval,
Packit Service 1d8f1c
                                      guint              prev_modifiers,
Packit Service 1d8f1c
                                      gpointer           user_data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    modifiers = normalize_modifiers (keyval, modifiers & priv->mask);
Packit Service 1d8f1c
    prev_modifiers = normalize_modifiers (prev_keyval, prev_modifiers & priv->mask);
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBusHotkey hotkey = {
Packit Service 1d8f1c
        .keyval = keyval,
Packit Service 1d8f1c
        .modifiers = modifiers,
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (modifiers & IBUS_RELEASE_MASK) {
Packit Service 1d8f1c
        /* previous key event must be a press key event */
Packit Service 1d8f1c
        if (prev_modifiers & IBUS_RELEASE_MASK)
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* modifiers should be same except the release bit */
Packit Service 1d8f1c
        if (modifiers != (prev_modifiers | IBUS_RELEASE_MASK))
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* If it is release key event,
Packit Service 1d8f1c
         * we need check if keyval is equal to the prev keyval.
Packit Service 1d8f1c
         * If keyval is not equal to the prev keyval,
Packit Service 1d8f1c
         * but both keyvals are modifier keys,
Packit Service 1d8f1c
         * we will still search it in hotkeys.
Packit Service 1d8f1c
         * It is for matching some key sequences like:
Packit Service 1d8f1c
         * Shift Down, Alt Down, Shift Up => Shift+Alt+Release - Shift hotkey
Packit Service 1d8f1c
         **/
Packit Service 1d8f1c
        if ((keyval != prev_keyval) &&
Packit Service 1d8f1c
            (is_modifier (keyval) == FALSE ||
Packit Service 1d8f1c
             is_modifier (prev_keyval) == FALSE))
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    GQuark event = (GQuark) GPOINTER_TO_UINT (g_tree_lookup (priv->hotkeys, &hotkey));
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (event != 0) {
Packit Service 1d8f1c
        g_signal_emit (profile, profile_signals[TRIGGER], event, user_data);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return event;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
GQuark
Packit Service 1d8f1c
ibus_hotkey_profile_lookup_hotkey (IBusHotkeyProfile *profile,
Packit Service 1d8f1c
                                   guint              keyval,
Packit Service 1d8f1c
                                   guint              modifiers)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusHotkeyProfilePrivate *priv;
Packit Service 1d8f1c
    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
Packit Service 1d8f1c
Packit Service 1d8f1c
    modifiers = normalize_modifiers (keyval, modifiers & priv->mask);
Packit Service 1d8f1c
Packit Service 1d8f1c
    IBusHotkey hotkey = {
Packit Service 1d8f1c
        .keyval = keyval,
Packit Service 1d8f1c
        .modifiers = modifiers,
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
Packit Service 1d8f1c
    return (GQuark) GPOINTER_TO_UINT (g_tree_lookup (priv->hotkeys, &hotkey));
Packit Service 1d8f1c
}