Blame ui/gtk3/switcher.vala

Packit Service 1d8f1c
/* vim:set et sts=4 sw=4:
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * ibus - The Input Bus
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * Copyright(c) 2011-2016 Peng Huang <shawn.p.huang@gmail.com>
Packit Service 1d8f1c
 * Copyright(c) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
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
Packit Service 1d8f1c
class Switcher : Gtk.Window {
Packit Service 1d8f1c
    private class IBusEngineButton : Gtk.Button {
Packit Service 1d8f1c
        public IBusEngineButton(IBus.EngineDesc engine, Switcher switcher) {
Packit Service 1d8f1c
            GLib.Object();
Packit Service 1d8f1c
Packit Service 1d8f1c
            var longname = engine.get_longname();
Packit Service 1d8f1c
            var textdomain = engine.get_textdomain();
Packit Service 1d8f1c
            this.transname = GLib.dgettext(textdomain, longname);
Packit Service 1d8f1c
Packit Service 1d8f1c
            var name = engine.get_name();
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (name.length < 4 || name[0:4] != "xkb:") {
Packit Service 1d8f1c
                IconWidget icon = new IconWidget(engine.get_icon(),
Packit Service 1d8f1c
                                                 Gtk.IconSize.DIALOG);
Packit Service 1d8f1c
                icon.set_halign(Gtk.Align.CENTER);
Packit Service 1d8f1c
                icon.set_valign(Gtk.Align.CENTER);
Packit Service 1d8f1c
                add(icon);
Packit Service 1d8f1c
            } else {
Packit Service 1d8f1c
                var language = switcher.get_xkb_language(engine);
Packit Service 1d8f1c
Packit Service 1d8f1c
                Gtk.Label label = new Gtk.Label(language);
Packit Service 1d8f1c
                label.set_halign(Gtk.Align.CENTER);
Packit Service 1d8f1c
                label.set_valign(Gtk.Align.CENTER);
Packit Service 1d8f1c
                string language_font = "Monospace Bold 16";
Packit Service 1d8f1c
                string markup = "%s".
Packit Service 1d8f1c
                        printf(language_font, language);
Packit Service 1d8f1c
Packit Service 1d8f1c
                label.set_markup(markup);
Packit Service 1d8f1c
Packit Service 1d8f1c
                int fixed_width, fixed_height;
Packit Service 1d8f1c
                Gtk.icon_size_lookup(Gtk.IconSize.DIALOG,
Packit Service 1d8f1c
                                     out fixed_width,
Packit Service 1d8f1c
                                     out fixed_height);
Packit Service 1d8f1c
                label.set_size_request(fixed_width, fixed_height);
Packit Service 1d8f1c
Packit Service 1d8f1c
                add(label);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        public string transname { get; set; }
Packit Service 1d8f1c
Packit Service 1d8f1c
        public override bool draw(Cairo.Context cr) {
Packit Service 1d8f1c
            base.draw(cr);
Packit Service 1d8f1c
            if (is_focus) {
Packit Service 1d8f1c
                cr.save();
Packit Service 1d8f1c
                cr.rectangle(
Packit Service 1d8f1c
                        0, 0, get_allocated_width(), get_allocated_height());
Packit Service 1d8f1c
                cr.set_source_rgba(0.0, 0.0, 1.0, 0.1);
Packit Service 1d8f1c
                cr.fill();
Packit Service 1d8f1c
                cr.restore();
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            return true;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    private Gtk.Box m_box;
Packit Service 1d8f1c
    private Gtk.Label m_label;
Packit Service 1d8f1c
    private IBusEngineButton[] m_buttons = {};
Packit Service 1d8f1c
    private IBus.EngineDesc[] m_engines;
Packit Service 1d8f1c
    private uint m_selected_engine;
Packit Service 1d8f1c
    private uint m_keyval;
Packit Service 1d8f1c
    private uint m_modifiers;
Packit Service 1d8f1c
    private Gdk.ModifierType m_primary_modifier;
Packit Service 1d8f1c
    private bool m_is_running = false;
Packit Service 1d8f1c
    private string m_input_context_path = "";
Packit Service 1d8f1c
    private GLib.MainLoop m_loop;
Packit Service 1d8f1c
    private int m_result = -1;
Packit Service 1d8f1c
    private IBus.EngineDesc? m_result_engine = null;
Packit Service 1d8f1c
    private uint m_popup_delay_time = 0;
Packit Service 1d8f1c
    private uint m_popup_delay_time_id = 0;
Packit Service 1d8f1c
    private int m_root_x;
Packit Service 1d8f1c
    private int m_root_y;
Packit Service 1d8f1c
    private double m_mouse_init_x;
Packit Service 1d8f1c
    private double m_mouse_init_y;
Packit Service 1d8f1c
    private bool   m_mouse_moved;
Packit Service 1d8f1c
    private GLib.HashTable<string, string> m_xkb_languages =
Packit Service 1d8f1c
            new GLib.HashTable<string, string>(GLib.str_hash,
Packit Service 1d8f1c
                                               GLib.str_equal);
Packit Service 1d8f1c
Packit Service 1d8f1c
    public Switcher() {
Packit Service 1d8f1c
        GLib.Object(
Packit Service 1d8f1c
            type : Gtk.WindowType.POPUP,
Packit Service 1d8f1c
            events : Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK,
Packit Service 1d8f1c
            window_position : Gtk.WindowPosition.CENTER,
Packit Service 1d8f1c
            accept_focus : true,
Packit Service 1d8f1c
            decorated : false,
Packit Service 1d8f1c
            modal : true,
Packit Service 1d8f1c
            focus_visible : true
Packit Service 1d8f1c
        );
Packit Service 1d8f1c
        Gtk.Box vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
Packit Service 1d8f1c
        add(vbox);
Packit Service 1d8f1c
        m_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
Packit Service 1d8f1c
        m_box.set_halign(Gtk.Align.CENTER);
Packit Service 1d8f1c
        m_box.set_valign(Gtk.Align.CENTER);
Packit Service 1d8f1c
        vbox.pack_start(m_box, true, true, 0);
Packit Service 1d8f1c
        m_label = new Gtk.Label("");
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* Set the accessible role of the label to a status bar so it
Packit Service 1d8f1c
         * will emit name changed events that can be used by screen
Packit Service 1d8f1c
         * readers.
Packit Service 1d8f1c
         */
Packit Service 1d8f1c
        Atk.Object obj = m_label.get_accessible();
Packit Service 1d8f1c
        obj.set_role (Atk.Role.STATUSBAR);
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* Use Gtk.Widget.set_margin_start() and
Packit Service 1d8f1c
         * Gtk.Widget.set_margin_top() since gtk 3.12 */
Packit Service 1d8f1c
        m_label.set_padding(3, 3);
Packit Service 1d8f1c
        vbox.pack_end(m_label, false, false, 0);
Packit Service 1d8f1c
Packit Service 1d8f1c
        grab_focus();
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public int run(uint              keyval,
Packit Service 1d8f1c
                   uint              state,
Packit Service 1d8f1c
                   Gdk.Event         event,
Packit Service 1d8f1c
                   IBus.EngineDesc[] engines,
Packit Service 1d8f1c
                   int               index,
Packit Service 1d8f1c
                   string            input_context_path) {
Packit Service 1d8f1c
        assert (m_loop == null);
Packit Service 1d8f1c
        assert (index < engines.length);
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_is_running = true;
Packit Service 1d8f1c
        m_keyval = keyval;
Packit Service 1d8f1c
        m_modifiers = state;
Packit Service 1d8f1c
        m_primary_modifier =
Packit Service 1d8f1c
            KeybindingManager.get_primary_modifier(
Packit Service 1d8f1c
                state & KeybindingManager.MODIFIER_FILTER);
Packit Service 1d8f1c
        m_selected_engine = m_result = index;
Packit Service 1d8f1c
        m_input_context_path = input_context_path;
Packit Service 1d8f1c
        m_result_engine = null;
Packit Service 1d8f1c
Packit Service 1d8f1c
        update_engines(engines);
Packit Service 1d8f1c
        /* Let gtk recalculate the window size. */
Packit Service 1d8f1c
        resize(1, 1);
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_label.set_text(m_buttons[index].transname);
Packit Service 1d8f1c
        m_buttons[index].grab_focus();
Packit Service 1d8f1c
Packit Service 1d8f1c
        // Avoid regressions.
Packit Service 1d8f1c
        if (m_popup_delay_time > 0) {
Packit Service 1d8f1c
            get_position(out m_root_x, out m_root_y);
Packit Service 1d8f1c
            // Pull the window from the screen so that the window gets
Packit Service 1d8f1c
            // the key press and release events but mouse does not select
Packit Service 1d8f1c
            // an IME unexpectedly.
Packit Service 1d8f1c
            move(-1000, -1000);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        show_all();
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (m_popup_delay_time > 0) {
Packit Service 1d8f1c
            // Restore the window position after m_popup_delay_time
Packit Service 1d8f1c
            m_popup_delay_time_id = GLib.Timeout.add(m_popup_delay_time,
Packit Service 1d8f1c
                                                     () => {
Packit Service 1d8f1c
                restore_window_position("timeout");
Packit Service 1d8f1c
                return false;
Packit Service 1d8f1c
            });
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        Gdk.Device pointer;
Packit Service 1d8f1c
#if VALA_0_34
Packit Service 1d8f1c
        Gdk.Seat seat = event.get_seat();
Packit Service 1d8f1c
        if (seat == null) {
Packit Service 1d8f1c
            var display = get_display();
Packit Service 1d8f1c
            seat = display.get_default_seat();
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        //keyboard = seat.get_keyboard();
Packit Service 1d8f1c
        pointer = seat.get_pointer();
Packit Service 1d8f1c
Packit Service 1d8f1c
        Gdk.GrabStatus status;
Packit Service 1d8f1c
        // Grab all keyboard events
Packit Service 1d8f1c
        status = seat.grab(get_window(),
Packit Service 1d8f1c
                           Gdk.SeatCapabilities.KEYBOARD,
Packit Service 1d8f1c
                           true,
Packit Service 1d8f1c
                           null,
Packit Service 1d8f1c
                           event,
Packit Service 1d8f1c
                           null);
Packit Service 1d8f1c
        if (status != Gdk.GrabStatus.SUCCESS)
Packit Service 1d8f1c
            warning("Grab keyboard failed! status = %d", status);
Packit Service 1d8f1c
        status = seat.grab(get_window(),
Packit Service 1d8f1c
                           Gdk.SeatCapabilities.POINTER,
Packit Service 1d8f1c
                           true,
Packit Service 1d8f1c
                           null,
Packit Service 1d8f1c
                           event,
Packit Service 1d8f1c
                           null);
Packit Service 1d8f1c
        if (status != Gdk.GrabStatus.SUCCESS)
Packit Service 1d8f1c
            warning("Grab pointer failed! status = %d", status);
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
        Gdk.Device device = event.get_device();
Packit Service 1d8f1c
        if (device == null) {
Packit Service 1d8f1c
            var display = get_display();
Packit Service 1d8f1c
            var device_manager = display.get_device_manager();
Packit Service 1d8f1c
/* The macro VALA_X_Y supports even numbers.
Packit Service 1d8f1c
 * http://git.gnome.org/browse/vala/commit/?id=294b374af6
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
#if VALA_0_16
Packit Service 1d8f1c
            device = device_manager.list_devices(Gdk.DeviceType.MASTER).data;
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
            unowned GLib.List<Gdk.Device> devices =
Packit Service 1d8f1c
                    device_manager.list_devices(Gdk.DeviceType.MASTER);
Packit Service 1d8f1c
            device = devices.data;
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        Gdk.Device keyboard;
Packit Service 1d8f1c
        if (device.get_source() == Gdk.InputSource.KEYBOARD) {
Packit Service 1d8f1c
            keyboard = device;
Packit Service 1d8f1c
            pointer = device.get_associated_device();
Packit Service 1d8f1c
        } else {
Packit Service 1d8f1c
            pointer = device;
Packit Service 1d8f1c
            keyboard = device.get_associated_device();
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        Gdk.GrabStatus status;
Packit Service 1d8f1c
        // Grab all keyboard events
Packit Service 1d8f1c
        status = keyboard.grab(get_window(),
Packit Service 1d8f1c
                               Gdk.GrabOwnership.NONE,
Packit Service 1d8f1c
                               true,
Packit Service 1d8f1c
                               Gdk.EventMask.KEY_PRESS_MASK |
Packit Service 1d8f1c
                               Gdk.EventMask.KEY_RELEASE_MASK,
Packit Service 1d8f1c
                               null,
Packit Service 1d8f1c
                               Gdk.CURRENT_TIME);
Packit Service 1d8f1c
        if (status != Gdk.GrabStatus.SUCCESS)
Packit Service 1d8f1c
            warning("Grab keyboard failed! status = %d", status);
Packit Service 1d8f1c
        // Grab all pointer events
Packit Service 1d8f1c
        status = pointer.grab(get_window(),
Packit Service 1d8f1c
                              Gdk.GrabOwnership.NONE,
Packit Service 1d8f1c
                              true,
Packit Service 1d8f1c
                              Gdk.EventMask.BUTTON_PRESS_MASK |
Packit Service 1d8f1c
                              Gdk.EventMask.BUTTON_RELEASE_MASK,
Packit Service 1d8f1c
                              null,
Packit Service 1d8f1c
                              Gdk.CURRENT_TIME);
Packit Service 1d8f1c
        if (status != Gdk.GrabStatus.SUCCESS)
Packit Service 1d8f1c
            warning("Grab pointer failed! status = %d", status);
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
        // Probably we can delete m_popup_delay_time in 1.6
Packit Service 1d8f1c
        pointer.get_position_double(null,
Packit Service 1d8f1c
                                    out m_mouse_init_x,
Packit Service 1d8f1c
                                    out m_mouse_init_y);
Packit Service 1d8f1c
        m_mouse_moved = false;
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_loop = new GLib.MainLoop();
Packit Service 1d8f1c
        m_loop.run();
Packit Service 1d8f1c
        m_loop = null;
Packit Service 1d8f1c
Packit Service 1d8f1c
#if VALA_0_34
Packit Service 1d8f1c
        seat.ungrab();
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
        keyboard.ungrab(Gdk.CURRENT_TIME);
Packit Service 1d8f1c
        pointer.ungrab(Gdk.CURRENT_TIME);
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
        hide();
Packit Service 1d8f1c
        // Make sure the switcher is hidden before returning from this function.
Packit Service 1d8f1c
        while (Gtk.events_pending())
Packit Service 1d8f1c
            Gtk.main_iteration ();
Packit Service 1d8f1c
Packit Service 1d8f1c
        GLib.assert(m_result < m_engines.length);
Packit Service 1d8f1c
        m_result_engine = m_engines[m_result];
Packit Service 1d8f1c
        m_is_running = false;
Packit Service 1d8f1c
Packit Service 1d8f1c
        return m_result;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* Based on metacity/src/ui/tabpopup.c:meta_ui_tab_popup_new */
Packit Service 1d8f1c
    private void update_engines(IBus.EngineDesc[] engines) {
Packit Service 1d8f1c
        foreach (var button in m_buttons) {
Packit Service 1d8f1c
            button.destroy();
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        m_buttons = {};
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (engines == null) {
Packit Service 1d8f1c
            m_engines = {};
Packit Service 1d8f1c
            return;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_engines = engines;
Packit Service 1d8f1c
        int max_label_width = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (int i = 0; i < m_engines.length; i++) {
Packit Service 1d8f1c
            var index = i;
Packit Service 1d8f1c
            var engine = m_engines[i];
Packit Service 1d8f1c
            var button = new IBusEngineButton(engine, this);
Packit Service 1d8f1c
            var longname = engine.get_longname();
Packit Service 1d8f1c
            var textdomain = engine.get_textdomain();
Packit Service 1d8f1c
            var transname = GLib.dgettext(textdomain, longname);
Packit Service 1d8f1c
            button.set_relief(Gtk.ReliefStyle.NONE);
Packit Service 1d8f1c
            button.add_events(Gdk.EventMask.POINTER_MOTION_MASK);
Packit Service 1d8f1c
            button.show();
Packit Service 1d8f1c
Packit Service 1d8f1c
            button.enter_notify_event.connect((e) => {
Packit Service 1d8f1c
                // avoid gtk_button_update_state()
Packit Service 1d8f1c
                return true;
Packit Service 1d8f1c
            });
Packit Service 1d8f1c
            button.motion_notify_event.connect((e) => {
Packit Service 1d8f1c
#if VALA_0_24
Packit Service 1d8f1c
                Gdk.EventMotion pe = e;
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
                Gdk.EventMotion *pe = &e;
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
                if (m_selected_engine == index)
Packit Service 1d8f1c
                    return false;
Packit Service 1d8f1c
                if (!m_mouse_moved &&
Packit Service 1d8f1c
                    m_mouse_init_x == pe.x_root &&
Packit Service 1d8f1c
                    m_mouse_init_y == pe.y_root) {
Packit Service 1d8f1c
                    return false;
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                m_mouse_moved = true;
Packit Service 1d8f1c
                button.grab_focus();
Packit Service 1d8f1c
                m_selected_engine = index;
Packit Service 1d8f1c
                return false;
Packit Service 1d8f1c
            });
Packit Service 1d8f1c
Packit Service 1d8f1c
            button.button_press_event.connect((e) => {
Packit Service 1d8f1c
                m_selected_engine = index;
Packit Service 1d8f1c
                m_result = (int)m_selected_engine;
Packit Service 1d8f1c
                m_loop.quit();
Packit Service 1d8f1c
                return true;
Packit Service 1d8f1c
            });
Packit Service 1d8f1c
Packit Service 1d8f1c
            button.transname = transname;
Packit Service 1d8f1c
            m_label.set_label(transname);
Packit Service 1d8f1c
Packit Service 1d8f1c
            int width;
Packit Service 1d8f1c
            m_label.get_preferred_width(null, out width);
Packit Service 1d8f1c
            max_label_width = int.max(max_label_width, width);
Packit Service 1d8f1c
Packit Service 1d8f1c
            m_box.pack_start(button, true, true);
Packit Service 1d8f1c
            m_buttons += button;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_label.set_text(m_buttons[0].transname);
Packit Service 1d8f1c
        m_label.set_ellipsize(Pango.EllipsizeMode.END);
Packit Service 1d8f1c
Packit Service 1d8f1c
        Gdk.Display display = Gdk.Display.get_default();
Packit Service 1d8f1c
        int screen_width = 0;
Packit Service 1d8f1c
#if VALA_0_34
Packit Service 1d8f1c
        // display.get_monitor_at_window() is null because of unrealized window
Packit Service 1d8f1c
        Gdk.Monitor monitor = display.get_primary_monitor();
Packit Service 1d8f1c
        Gdk.Rectangle area = monitor.get_geometry();
Packit Service 1d8f1c
        screen_width = area.width;
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
        Gdk.Screen screen = (display != null) ?
Packit Service 1d8f1c
                display.get_default_screen() : null;
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (screen != null) {
Packit Service 1d8f1c
            screen_width = screen.get_width();
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (screen_width > 0 && max_label_width > (screen_width / 4)) {
Packit Service 1d8f1c
            max_label_width = screen_width / 4;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* add random padding */
Packit Service 1d8f1c
        max_label_width += 20;
Packit Service 1d8f1c
        set_default_size(max_label_width, -1);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    private void next_engine() {
Packit Service 1d8f1c
        if (m_selected_engine == m_engines.length - 1)
Packit Service 1d8f1c
            m_selected_engine = 0;
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            m_selected_engine ++;
Packit Service 1d8f1c
        m_label.set_text(m_buttons[m_selected_engine].transname);
Packit Service 1d8f1c
        set_focus(m_buttons[m_selected_engine]);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    private void previous_engine() {
Packit Service 1d8f1c
        if (m_selected_engine == 0)
Packit Service 1d8f1c
            m_selected_engine = m_engines.length - 1;
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            m_selected_engine --;
Packit Service 1d8f1c
        m_label.set_text(m_buttons[m_selected_engine].transname);
Packit Service 1d8f1c
        set_focus(m_buttons[m_selected_engine]);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    private void restore_window_position(string debug_str) {
Packit Service 1d8f1c
        debug("restore_window_position %s: (%ld, %ld)\n",
Packit Service 1d8f1c
                debug_str, m_root_x, m_root_y);
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (m_popup_delay_time_id == 0) {
Packit Service 1d8f1c
            return;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        GLib.Source.remove(m_popup_delay_time_id);
Packit Service 1d8f1c
        m_popup_delay_time_id = 0;
Packit Service 1d8f1c
        move(m_root_x, m_root_y);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* override virtual functions */
Packit Service 1d8f1c
    public override void show() {
Packit Service 1d8f1c
        base.show();
Packit Service 1d8f1c
        set_focus_visible(true);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public override bool key_press_event(Gdk.EventKey e) {
Packit Service 1d8f1c
        bool retval = true;
Packit Service 1d8f1c
Packit Service 1d8f1c
/* Gdk.EventKey is changed to the pointer.
Packit Service 1d8f1c
 * https://git.gnome.org/browse/vala/commit/?id=598942f1
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
#if VALA_0_24
Packit Service 1d8f1c
        Gdk.EventKey pe = e;
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
        Gdk.EventKey *pe = &e;
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (m_popup_delay_time > 0) {
Packit Service 1d8f1c
            restore_window_position("pressed");
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        do {
Packit Service 1d8f1c
            uint modifiers = KeybindingManager.MODIFIER_FILTER & pe.state;
Packit Service 1d8f1c
Packit Service 1d8f1c
            if ((modifiers != m_modifiers) &&
Packit Service 1d8f1c
                (modifiers != (m_modifiers | Gdk.ModifierType.SHIFT_MASK))) {
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (pe.keyval == m_keyval) {
Packit Service 1d8f1c
                if (modifiers == m_modifiers)
Packit Service 1d8f1c
                    next_engine();
Packit Service 1d8f1c
                else // modififers == m_modifiers | SHIFT_MASK
Packit Service 1d8f1c
                    previous_engine();
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
Packit Service 1d8f1c
            switch (pe.keyval) {
Packit Service 1d8f1c
                case 0x08fb: /* leftarrow */
Packit Service 1d8f1c
                case 0xff51: /* Left */
Packit Service 1d8f1c
                    previous_engine();
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
                case 0x08fc: /* uparrow */
Packit Service 1d8f1c
                case 0xff52: /* Up */
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
                case 0x08fd: /* rightarrow */
Packit Service 1d8f1c
                case 0xff53: /* Right */
Packit Service 1d8f1c
                    next_engine();
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
                case 0x08fe: /* downarrow */
Packit Service 1d8f1c
                case 0xff54: /* Down */
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
                default:
Packit Service 1d8f1c
                    debug("0x%04x", pe.keyval);
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        } while (false);
Packit Service 1d8f1c
        return retval;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public override bool key_release_event(Gdk.EventKey e) {
Packit Service 1d8f1c
#if VALA_0_24
Packit Service 1d8f1c
        Gdk.EventKey pe = e;
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
        Gdk.EventKey *pe = &e;
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (KeybindingManager.primary_modifier_still_pressed((Gdk.Event) pe,
Packit Service 1d8f1c
            m_primary_modifier)) {
Packit Service 1d8f1c
            return true;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        // if e.type == Gdk.EventType.KEY_RELEASE, m_loop is already null.
Packit Service 1d8f1c
        if (m_loop == null) {
Packit Service 1d8f1c
            return false;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (m_popup_delay_time > 0) {
Packit Service 1d8f1c
            if (m_popup_delay_time_id != 0) {
Packit Service 1d8f1c
                GLib.Source.remove(m_popup_delay_time_id);
Packit Service 1d8f1c
                m_popup_delay_time_id = 0;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_loop.quit();
Packit Service 1d8f1c
        m_result = (int)m_selected_engine;
Packit Service 1d8f1c
        return true;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public void set_popup_delay_time(uint popup_delay_time) {
Packit Service 1d8f1c
        m_popup_delay_time = popup_delay_time;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public string get_xkb_language(IBus.EngineDesc engine) {
Packit Service 1d8f1c
        var name = engine.get_name();
Packit Service 1d8f1c
Packit Service 1d8f1c
        assert(name[0:4] == "xkb:");
Packit Service 1d8f1c
Packit Service 1d8f1c
        var language = m_xkb_languages[name];
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (language != null)
Packit Service 1d8f1c
            return language;
Packit Service 1d8f1c
Packit Service 1d8f1c
        language = engine.get_language();
Packit Service 1d8f1c
        int length = language.length;
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* Maybe invalid layout */
Packit Service 1d8f1c
        if (length < 2)
Packit Service 1d8f1c
            return language;
Packit Service 1d8f1c
Packit Service 1d8f1c
        language = language.up();
Packit Service 1d8f1c
Packit Service 1d8f1c
        int index = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
        foreach (var saved_language in m_xkb_languages.get_values()) {
Packit Service 1d8f1c
            if (language == saved_language[0:length])
Packit Service 1d8f1c
                index++;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (index > 0) {
Packit Service 1d8f1c
            unichar u = 0x2081 + index;
Packit Service 1d8f1c
            language = "%s%s".printf(language, u.to_string());
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        m_xkb_languages.insert(name, language);
Packit Service 1d8f1c
        return language;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public bool is_running() {
Packit Service 1d8f1c
        return m_is_running;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public string get_input_context_path() {
Packit Service 1d8f1c
        return m_input_context_path;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public IBus.EngineDesc? get_selected_engine() {
Packit Service 1d8f1c
        return m_result_engine;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    public void reset() {
Packit Service 1d8f1c
        m_input_context_path = "";
Packit Service 1d8f1c
        m_result = -1;
Packit Service 1d8f1c
        m_result_engine = null;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}