*/
class Panel : IBus.PanelService {
+ private class Keybinding {
+ public Keybinding(uint keysym,
+ Gdk.ModifierType modifiers,
+ bool reverse) {
+ this.keysym = keysym;
+ this.modifiers = modifiers;
+ this.reverse = reverse;
+ }
+
+ public uint keysym { get; set; }
+ public Gdk.ModifierType modifiers { get; set; }
+ public bool reverse { get; set; }
+ }
+
private IBus.Bus m_bus;
private IBus.Config m_config;
private Gtk.StatusIcon m_status_icon;
private GLib.Pid m_setup_pid = 0;
private Gtk.AboutDialog m_about_dialog;
private Gtk.CssProvider m_css_provider;
+ private int m_switcher_delay_time = 400;
+ private bool m_use_system_keyboard_layout = false;
private const string ACCELERATOR_SWITCH_IME_FOREWARD = "<Control>space";
- private uint m_switch_keysym = 0;
- private Gdk.ModifierType m_switch_modifiers = 0;
+ private GLib.List<Keybinding> m_keybindings = new GLib.List<Keybinding>();
public Panel(IBus.Bus bus) {
GLib.assert(bus.is_connected());
m_candidate_panel.page_down.connect((w) => this.page_down());
m_switcher = new Switcher();
- bind_switch_shortcut();
+ // The initial shortcut is "<Control>space"
+ bind_switch_shortcut(null);
+
+ if (m_switcher_delay_time >= 0) {
+ m_switcher.set_popup_delay_time((uint) m_switcher_delay_time);
+ }
m_property_manager = new PropertyManager();
m_property_manager.property_activate.connect((k, s) => {
unbind_switch_shortcut();
}
- private void bind_switch_shortcut() {
- var keybinding_manager = KeybindingManager.get_instance();
+ private void keybinding_manager_bind(KeybindingManager keybinding_manager,
+ string? accelerator) {
+ uint switch_keysym = 0;
+ Gdk.ModifierType switch_modifiers = 0;
+ Gdk.ModifierType reverse_modifier = Gdk.ModifierType.SHIFT_MASK;
+ Keybinding keybinding;
- var accelerator = ACCELERATOR_SWITCH_IME_FOREWARD;
Gtk.accelerator_parse(accelerator,
- out m_switch_keysym, out m_switch_modifiers);
+ out switch_keysym, out switch_modifiers);
- // Map virtual modifiers to (i.e.Mod2, Mod3, ...)
+ // 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 ((m_switch_modifiers & VIRTUAL_MODIFIERS) != 0) {
+ 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 m_switch_modifiers);
+ ref switch_modifiers);
#else
- if ((m_switch_modifiers & Gdk.ModifierType.SUPER_MASK) != 0)
- m_switch_modifiers |= Gdk.ModifierType.MOD4_MASK;
- if ((m_switch_modifiers & Gdk.ModifierType.HYPER_MASK) != 0)
- m_switch_modifiers |= Gdk.ModifierType.MOD4_MASK;
+ 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
- m_switch_modifiers &= ~VIRTUAL_MODIFIERS;
+ switch_modifiers &= ~VIRTUAL_MODIFIERS;
}
- if (m_switch_keysym == 0 && m_switch_modifiers == 0) {
+ if (switch_keysym == 0 && switch_modifiers == 0) {
warning("Parse accelerator '%s' failed!", accelerator);
return;
}
- keybinding_manager.bind(m_switch_keysym, m_switch_modifiers,
+ keybinding = new Keybinding(switch_keysym,
+ switch_modifiers,
+ false);
+ m_keybindings.append(keybinding);
+
+ keybinding_manager.bind(switch_keysym, switch_modifiers,
(e) => handle_engine_switch(e, false));
// accelerator already has Shift mask
- if ((m_switch_modifiers & Gdk.ModifierType.SHIFT_MASK) != 0)
+ if ((switch_modifiers & reverse_modifier) != 0) {
return;
+ }
- keybinding_manager.bind(m_switch_keysym,
- m_switch_modifiers | Gdk.ModifierType.SHIFT_MASK,
+ switch_modifiers |= reverse_modifier;
+
+ keybinding = new Keybinding(switch_keysym,
+ switch_modifiers,
+ true);
+ m_keybindings.append(keybinding);
+
+ keybinding_manager.bind(switch_keysym, switch_modifiers,
(e) => handle_engine_switch(e, true));
}
+ private void bind_switch_shortcut(Variant? variant) {
+ string[] accelerators = {};
+ Variant var_trigger = variant;
+
+ if (var_trigger == null && m_config != null) {
+ var_trigger = m_config.get_value("general/hotkey",
+ "triggers");
+ }
+
+ if (var_trigger != null) {
+ accelerators = var_trigger.dup_strv();
+ } else {
+ accelerators += ACCELERATOR_SWITCH_IME_FOREWARD;
+ }
+
+ var keybinding_manager = KeybindingManager.get_instance();
+
+ foreach (var accelerator in accelerators) {
+ keybinding_manager_bind(keybinding_manager, accelerator);
+ }
+ }
+
private void unbind_switch_shortcut() {
var keybinding_manager = KeybindingManager.get_instance();
- if (m_switch_keysym == 0 && m_switch_modifiers == 0)
- return;
+ unowned GLib.List<Keybinding> keybindings = m_keybindings;
- keybinding_manager.unbind(m_switch_keysym, m_switch_modifiers);
- keybinding_manager.unbind(m_switch_keysym,
- m_switch_modifiers | Gdk.ModifierType.SHIFT_MASK);
+ while (keybindings != null) {
+ Keybinding keybinding = keybindings.data;
- m_switch_keysym = 0;
- m_switch_modifiers = 0;
+ keybinding_manager.unbind(keybinding.keysym,
+ keybinding.modifiers);
+ keybindings = keybindings.next;
+ }
+
+ m_keybindings = null;
}
private void set_custom_font() {
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
}
+ private void set_switcher_delay_time(Variant? variant) {
+ Variant var_switcher_delay_time = variant;
+
+ if (var_switcher_delay_time == null) {
+ var_switcher_delay_time = m_config.get_value("general",
+ "switcher-delay-time");
+ }
+
+ if (var_switcher_delay_time == null) {
+ return;
+ }
+
+ m_switcher_delay_time = var_switcher_delay_time.get_int32();
+
+ if (m_switcher_delay_time >= 0) {
+ m_switcher.set_popup_delay_time((uint) m_switcher_delay_time);
+ }
+ }
+
+ private void set_use_system_keyboard_layout(Variant? variant) {
+ Variant var_use_system_kbd_layout = variant;
+
+ if (var_use_system_kbd_layout == null) {
+ var_use_system_kbd_layout = m_config.get_value(
+ "general",
+ "use_system_keyboard_layout");
+ }
+
+ if (var_use_system_kbd_layout == null) {
+ return;
+ }
+
+ m_use_system_keyboard_layout = var_use_system_kbd_layout.get_boolean();
+ }
+
public void set_config(IBus.Config config) {
if (m_config != null) {
m_config.value_changed.disconnect(config_value_changed_cb);
m_config.value_changed.connect(config_value_changed_cb);
m_config.watch("general", "preload_engines");
m_config.watch("general", "engines_order");
+ m_config.watch("general", "switcher_delay_time");
+ m_config.watch("general", "use_system_keyboard_layout");
+ m_config.watch("general/hotkey", "triggers");
m_config.watch("panel", "custom_font");
m_config.watch("panel", "use_custom_font");
+ // Update m_use_system_keyboard_layout before update_engines()
+ // is called.
+ set_use_system_keyboard_layout(null);
update_engines(m_config.get_value("general", "preload_engines"),
m_config.get_value("general", "engines_order"));
+ unbind_switch_shortcut();
+ bind_switch_shortcut(null);
+ set_switcher_delay_time(null);
} else {
update_engines(null, null);
}
set_custom_font();
}
+ private void exec_setxkbmap(IBus.EngineDesc engine) {
+ string layout = engine.get_layout();
+ string variant = engine.get_layout_variant();
+ string option = engine.get_layout_option();
+ string standard_error = null;
+ int exit_status = 0;
+ string[] args = { "setxkbmap" };
+
+ if (layout != null && layout != "" && layout != "default") {
+ args += "-layout";
+ args += layout;
+ }
+ if (variant != null && variant != "" && variant != "default") {
+ args += "-variant";
+ args += variant;
+ }
+ if (option != null && option != "" && option != "default") {
+ /*TODO: Need to get the session XKB options */
+ args += "-option";
+ args += "-option";
+ args += option;
+ }
+
+ if (args.length == 1) {
+ return;
+ }
+
+ try {
+ if (!GLib.Process.spawn_sync(null, args, null,
+ GLib.SpawnFlags.SEARCH_PATH,
+ null, null,
+ out standard_error,
+ out exit_status)) {
+ warning("Switch xkb layout to %s failed.",
+ engine.get_layout());
+ }
+ } catch (GLib.SpawnError e) {
+ warning("Execute setxkbmap failed: %s", e.message);
+ }
+
+ if (exit_status != 0) {
+ warning("Execute setxkbmap failed: %s", standard_error ?? "(null)");
+ }
+ }
+
private void switch_engine(int i, bool force = false) {
GLib.assert(i >= 0 && i < m_engines.length);
return;
}
// set xkb layout
- string cmdline = "setxkbmap %s".printf(engine.get_layout());
- try {
- if (!GLib.Process.spawn_command_line_sync(cmdline)) {
- warning("Switch xkb layout to %s failed.",
- engine.get_layout());
- }
- } catch (GLib.SpawnError e) {
- warning("Execute setxkbmap failed: %s", e.message);
+ if (!m_use_system_keyboard_layout) {
+ exec_setxkbmap(engine);
}
}
return;
}
+ if (section == "general/hotkey" && name == "triggers") {
+ unbind_switch_shortcut();
+ bind_switch_shortcut(variant);
+ return;
+ }
+
if (section == "panel" && (name == "custom_font" ||
name == "use_custom_font")) {
set_custom_font();
return;
}
+
+ if (section == "general" && name == "switcher_delay_time") {
+ set_switcher_delay_time(variant);
+ return;
+ }
+
+ if (section == "general" && name == "use_system_keyboard_layout") {
+ set_use_system_keyboard_layout(variant);
+ return;
+ }
}
private void handle_engine_switch(Gdk.Event event, bool revert) {
if (m_engines.length <= 1)
return;
+ uint keyval = event.key.keyval;
+ uint modifiers = KeybindingManager.MODIFIER_FILTER & event.key.state;
+
uint primary_modifiers =
KeybindingManager.get_primary_modifier(event.key.state);
bool pressed = KeybindingManager.primary_modifier_still_pressed(
event, primary_modifiers);
- if (pressed) {
+
+ if (revert) {
+ modifiers &= ~Gdk.ModifierType.SHIFT_MASK;
+ }
+
+ if (pressed && m_switcher_delay_time >= 0) {
int i = revert ? m_engines.length - 1 : 1;
- i = m_switcher.run(m_switch_keysym, m_switch_modifiers, event,
- m_engines, i);
+ i = m_switcher.run(keyval, modifiers, event, m_engines, i);
if (i < 0) {
debug("switch cancelled");
} else {
}
}
+ private void run_preload_engines(IBus.EngineDesc[] engines, int index) {
+ string[] names = {};
+
+ if (engines.length <= index) {
+ return;
+ }
+
+ names += engines[index].get_name();
+ m_bus.preload_engines_async(names, -1, null);
+ }
+
private void update_engines(GLib.Variant? var_engines,
GLib.Variant? var_order) {
string[] engine_names = null;
if (m_engines.length == 0) {
m_engines = engines;
switch_engine(0, true);
+ run_preload_engines(engines, 1);
} else {
var current_engine = m_engines[0];
m_engines = engines;
for (i = 0; i < m_engines.length; i++) {
if (current_engine.get_name() == engines[i].get_name()) {
switch_engine(i);
+ if (i != 0) {
+ run_preload_engines(engines, 0);
+ } else {
+ run_preload_engines(engines, 1);
+ }
return;
}
}
switch_engine(0, true);
+ run_preload_engines(engines, 1);
}
}
m_ime_menu.append(new Gtk.SeparatorMenuItem());
- int width, height;
- Gtk.icon_size_lookup(Gtk.IconSize.MENU, out width, out height);
-
// Append IMEs
foreach (var engine in m_engines) {
var language = engine.get_language();
var item = new Gtk.ImageMenuItem.with_label(
"%s - %s".printf (IBus.get_language_name(language), longname));
if (engine.get_icon() != "") {
- var icon = new IconWidget(engine.get_icon(), width);
+ var icon = new IconWidget(engine.get_icon(), Gtk.IconSize.MENU);
item.set_image(icon);
}
// Make a copy of engine to workaround a bug in vala.
if (icon_name[0] == '/')
m_status_icon.set_from_file(icon_name);
- else
- m_status_icon.set_from_icon_name(icon_name);
+ else {
+ var theme = Gtk.IconTheme.get_default();
+ if (theme.lookup_icon(icon_name, 48, 0) != null) {
+ m_status_icon.set_from_icon_name(icon_name);
+ } else {
+ m_status_icon.set_from_icon_name("ibus-engine");
+ }
+ }
if (engine == null)
return;