Blob Blame History Raw
/* vim:set et sts=4 sw=4:
 *
 * ibus - The Input Bus
 *
 * Copyright(c) 2018 Peng Huang <shawn.p.huang@gmail.com>
 * Copyright(c) 2018 Takao Fujwiara <takao.fujiwara1@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

/* This file depends on keybindingmanager.vala */

class BindingCommon {
    public enum KeyEventFuncType {
        ANY,
        IME_SWITCHER,
        EMOJI_TYPING,
    }

    public class Keybinding : GLib.Object {
        public Keybinding(uint             keysym,
                          Gdk.ModifierType modifiers,
                          bool             reverse,
                          KeyEventFuncType ftype) {
            this.keysym = keysym;
            this.modifiers = modifiers;
            this.reverse = reverse;
            this.ftype = ftype;
        }

        public uint keysym { get; set; }
        public Gdk.ModifierType modifiers { get; set; }
        public bool reverse { get; set; }
        public KeyEventFuncType ftype { get; set; }
    }

    public delegate void KeybindingFuncHandlerFunc(Gdk.Event event);

    public static void
    keybinding_manager_bind(KeybindingManager           keybinding_manager,
                            ref GLib.List<Keybinding>   keybindings,
                            string?                     accelerator,
                            KeyEventFuncType            ftype,
                            KeybindingManager.KeybindingHandlerFunc
                                                        handler_normal,
                            KeybindingManager.KeybindingHandlerFunc?
                                                        handler_reverse) {
        uint switch_keysym = 0;
        Gdk.ModifierType switch_modifiers = 0;
        Gdk.ModifierType reverse_modifier = Gdk.ModifierType.SHIFT_MASK;
        Keybinding keybinding;

        Gtk.accelerator_parse(accelerator,
                out switch_keysym, out switch_modifiers);

        // Map virtual modifiers to (i.e. Mod2, Mod3, ...)
        const Gdk.ModifierType VIRTUAL_MODIFIERS = (
                Gdk.ModifierType.SUPER_MASK |
                Gdk.ModifierType.HYPER_MASK |
                Gdk.ModifierType.META_MASK);
        if ((switch_modifiers & VIRTUAL_MODIFIERS) != 0) {
        // workaround a bug in gdk vapi vala > 0.18
        // https://bugzilla.gnome.org/show_bug.cgi?id=677559
#if VALA_0_18
            Gdk.Keymap.get_default().map_virtual_modifiers(
                    ref switch_modifiers);
#else
            if ((switch_modifiers & Gdk.ModifierType.SUPER_MASK) != 0)
                switch_modifiers |= Gdk.ModifierType.MOD4_MASK;
            if ((switch_modifiers & Gdk.ModifierType.HYPER_MASK) != 0)
                switch_modifiers |= Gdk.ModifierType.MOD4_MASK;
#endif
            switch_modifiers &= ~VIRTUAL_MODIFIERS;
        }

        if (switch_keysym == 0 && switch_modifiers == 0) {
            warning("Parse accelerator '%s' failed!", accelerator);
            return;
        }

        keybinding = new Keybinding(switch_keysym,
                                    switch_modifiers,
                                    false,
                                    ftype);
        keybindings.append(keybinding);

        keybinding_manager.bind(switch_keysym, switch_modifiers,
                                handler_normal);
        if (ftype == KeyEventFuncType.EMOJI_TYPING) {
            return;
        }

        // accelerator already has Shift mask
        if ((switch_modifiers & reverse_modifier) != 0) {
            return;
        }

        switch_modifiers |= reverse_modifier;

        keybinding = new Keybinding(switch_keysym,
                                    switch_modifiers,
                                    true,
                                    ftype);
        keybindings.append(keybinding);

        if (ftype == KeyEventFuncType.IME_SWITCHER) {
            keybinding_manager.bind(switch_keysym, switch_modifiers,
                                    handler_reverse);
        }
        return;
    }

    public static void
    unbind_switch_shortcut(KeyEventFuncType      ftype,
                           GLib.List<Keybinding> keybindings) {
        var keybinding_manager = KeybindingManager.get_instance();

        while (keybindings != null) {
            Keybinding keybinding = keybindings.data;

            if (ftype == KeyEventFuncType.ANY ||
                ftype == keybinding.ftype) {
                keybinding_manager.unbind(keybinding.keysym,
                                          keybinding.modifiers);
            }
            keybindings = keybindings.next;
        }
    }

    public static void
    set_custom_font(GLib.Settings?       settings_panel,
                    GLib.Settings?       settings_emoji,
                    ref Gtk.CssProvider? css_provider) {
        Gdk.Display display = Gdk.Display.get_default();
        Gdk.Screen screen = (display != null) ?
                display.get_default_screen() : null;

        if (screen == null) {
            warning("Could not open display.");
            return;
        }

        if (settings_emoji != null) {
            string emoji_font = settings_emoji.get_string("font");
            if (emoji_font == null) {
                warning("No config emoji:font.");
                return;
            }
            IBusEmojier.set_emoji_font(emoji_font);
        }

        if (settings_panel == null)
            return;

        bool use_custom_font = settings_panel.get_boolean("use-custom-font");

        if (css_provider != null) {
            Gtk.StyleContext.remove_provider_for_screen(screen,
                                                        css_provider);
            css_provider = null;
        }

        if (use_custom_font == false) {
            return;
        }

        string custom_font = settings_panel.get_string("custom-font");
        if (custom_font == null) {
            warning("No config panel:custom-font.");
            return;
        }

        Pango.FontDescription font_desc =
                Pango.FontDescription.from_string(custom_font);
        string font_family = font_desc.get_family();
        int font_size = font_desc.get_size() / Pango.SCALE;
        string data;

        if (Gtk.MAJOR_VERSION < 3 ||
            (Gtk.MAJOR_VERSION == 3 && Gtk.MINOR_VERSION < 20)) {
            data = "GtkLabel { font: %s; }".printf(custom_font);
        } else {
            data = "label { font-family: %s; font-size: %dpt; }"
                           .printf(font_family, font_size);
        }

        css_provider = new Gtk.CssProvider();

        try {
            css_provider.load_from_data(data, -1);
        } catch (GLib.Error e) {
            warning("Failed css_provider_from_data: %s: %s", custom_font,
                                                             e.message);
            return;
        }

        Gtk.StyleContext.add_provider_for_screen(
                screen,
                css_provider,
                Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
    }
}