|
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) 2014 Red Hat, Inc.
|
|
Packit Service |
1d8f1c |
* Copyright(c) 2014 Peng Huang <shawn.p.huang@gmail.com>
|
|
Packit Service |
1d8f1c |
* Copyright(c) 2014 Takao Fujiwara <tfujiwar@redhat.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 XKBLayout
|
|
Packit Service |
1d8f1c |
{
|
|
Packit Service |
1d8f1c |
private const string XKB_COMMAND = "setxkbmap";
|
|
Packit Service |
1d8f1c |
private const string XKB_QUERY_ARG = "-query";
|
|
Packit Service |
1d8f1c |
private const string XKB_LAYOUT_ARG = "-layout";
|
|
Packit Service |
1d8f1c |
private const string XMODMAP_COMMAND = "xmodmap";
|
|
Packit Service |
1d8f1c |
private const string[] XMODMAP_KNOWN_FILES = {".xmodmap", ".xmodmaprc",
|
|
Packit Service |
1d8f1c |
".Xmodmap", ".Xmodmaprc"};
|
|
Packit Service |
1d8f1c |
private string[] m_xkb_latin_layouts = {};
|
|
Packit Service |
1d8f1c |
private string m_default_layout = "";
|
|
Packit Service |
1d8f1c |
private string m_default_variant = "";
|
|
Packit Service |
1d8f1c |
private string m_default_option = "";
|
|
Packit Service |
1d8f1c |
private bool m_use_xmodmap = true;
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
public XKBLayout() {
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
public void set_latin_layouts(string[] xkb_latin_layouts) {
|
|
Packit Service |
1d8f1c |
m_xkb_latin_layouts = xkb_latin_layouts;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
public static void get_layout(out string layout,
|
|
Packit Service |
1d8f1c |
out string variant,
|
|
Packit Service |
1d8f1c |
out string option) {
|
|
Packit Service |
1d8f1c |
string[] exec_command = {};
|
|
Packit Service |
1d8f1c |
exec_command += XKB_COMMAND;
|
|
Packit Service |
1d8f1c |
exec_command += XKB_QUERY_ARG;
|
|
Packit Service |
1d8f1c |
string standard_output = null;
|
|
Packit Service |
1d8f1c |
string standard_error = null;
|
|
Packit Service |
1d8f1c |
int exit_status = 0;
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
layout = "";
|
|
Packit Service |
1d8f1c |
variant = "";
|
|
Packit Service |
1d8f1c |
option = "";
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
try {
|
|
Packit Service |
1d8f1c |
GLib.Process.spawn_sync(null,
|
|
Packit Service |
1d8f1c |
exec_command,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
GLib.SpawnFlags.SEARCH_PATH,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
out standard_output,
|
|
Packit Service |
1d8f1c |
out standard_error,
|
|
Packit Service |
1d8f1c |
out exit_status);
|
|
Packit Service |
1d8f1c |
} catch (GLib.SpawnError err) {
|
|
Packit Service |
1d8f1c |
stderr.printf("IBUS_ERROR: %s\n", err.message);
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
if (exit_status != 0) {
|
|
Packit Service |
1d8f1c |
stderr.printf("IBUS_ERROR: %s\n", standard_error ?? "");
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
if (standard_output == null) {
|
|
Packit Service |
1d8f1c |
return;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
foreach (string line in standard_output.split("\n")) {
|
|
Packit Service |
1d8f1c |
string element = "layout:";
|
|
Packit Service |
1d8f1c |
string retval = "";
|
|
Packit Service |
1d8f1c |
if (line.has_prefix(element)) {
|
|
Packit Service |
1d8f1c |
retval = line[element.length:line.length];
|
|
Packit Service |
1d8f1c |
if (retval != null) {
|
|
Packit Service |
1d8f1c |
retval = retval.strip();
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
layout = retval;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
element = "variant:";
|
|
Packit Service |
1d8f1c |
retval = "";
|
|
Packit Service |
1d8f1c |
if (line.has_prefix(element)) {
|
|
Packit Service |
1d8f1c |
retval = line[element.length:line.length];
|
|
Packit Service |
1d8f1c |
if (retval != null) {
|
|
Packit Service |
1d8f1c |
retval = retval.strip();
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
variant = retval;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
element = "options:";
|
|
Packit Service |
1d8f1c |
retval = "";
|
|
Packit Service |
1d8f1c |
if (line.has_prefix(element)) {
|
|
Packit Service |
1d8f1c |
retval = line[element.length:line.length];
|
|
Packit Service |
1d8f1c |
if (retval != null) {
|
|
Packit Service |
1d8f1c |
retval = retval.strip();
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
option = retval;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
public void set_layout(IBus.EngineDesc engine) {
|
|
Packit Service |
1d8f1c |
string layout = engine.get_layout();
|
|
Packit Service |
1d8f1c |
string variant = engine.get_layout_variant();
|
|
Packit Service |
1d8f1c |
string option = engine.get_layout_option();
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
assert (layout != null);
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
/* If the layout is "default", return here so that the current
|
|
Packit Service |
1d8f1c |
* keymap is not changed.
|
|
Packit Service |
1d8f1c |
* Some engines do not wish to change the current keymap.
|
|
Packit Service |
1d8f1c |
*/
|
|
Packit Service |
1d8f1c |
if (layout == "default" &&
|
|
Packit Service |
1d8f1c |
(variant == "default" || variant == "") &&
|
|
Packit Service |
1d8f1c |
(option == "default" || option == "")) {
|
|
Packit Service |
1d8f1c |
return;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
bool need_us_layout = false;
|
|
Packit Service |
1d8f1c |
if (variant != "eng")
|
|
Packit Service |
1d8f1c |
need_us_layout = layout in m_xkb_latin_layouts;
|
|
Packit Service |
1d8f1c |
if (!need_us_layout && variant != null)
|
|
Packit Service |
1d8f1c |
need_us_layout =
|
|
Packit Service |
1d8f1c |
"%s(%s)".printf(layout, variant) in m_xkb_latin_layouts;
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (m_default_layout == "") {
|
|
Packit Service |
1d8f1c |
get_layout (out m_default_layout,
|
|
Packit Service |
1d8f1c |
out m_default_variant,
|
|
Packit Service |
1d8f1c |
out m_default_option);
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (layout == "default" || layout == "") {
|
|
Packit Service |
1d8f1c |
layout = m_default_layout;
|
|
Packit Service |
1d8f1c |
variant = m_default_variant;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (layout == "") {
|
|
Packit Service |
1d8f1c |
warning("Could not get the correct layout");
|
|
Packit Service |
1d8f1c |
return;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (option == "default" || option == "") {
|
|
Packit Service |
1d8f1c |
option = m_default_option;
|
|
Packit Service |
1d8f1c |
} else {
|
|
Packit Service |
1d8f1c |
if (!(option in m_default_option.split(","))) {
|
|
Packit Service |
1d8f1c |
option = "%s,%s".printf(m_default_option, option);
|
|
Packit Service |
1d8f1c |
} else {
|
|
Packit Service |
1d8f1c |
option = m_default_option;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (need_us_layout) {
|
|
Packit Service |
1d8f1c |
layout += ",us";
|
|
Packit Service |
1d8f1c |
if (variant != null) {
|
|
Packit Service |
1d8f1c |
variant += ",";
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
string[] args = {};
|
|
Packit Service |
1d8f1c |
args += XKB_COMMAND;
|
|
Packit Service |
1d8f1c |
args += XKB_LAYOUT_ARG;
|
|
Packit Service |
1d8f1c |
args += layout;
|
|
Packit Service |
1d8f1c |
if (variant != null && variant != "" && variant != "default") {
|
|
Packit Service |
1d8f1c |
args += "-variant";
|
|
Packit Service |
1d8f1c |
args += variant;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
if (option != null && option != "" && option != "default") {
|
|
Packit Service |
1d8f1c |
/*TODO: Need to get the session XKB options */
|
|
Packit Service |
1d8f1c |
args += "-option";
|
|
Packit Service |
1d8f1c |
args += "-option";
|
|
Packit Service |
1d8f1c |
args += option;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
string standard_error = null;
|
|
Packit Service |
1d8f1c |
int exit_status = 0;
|
|
Packit Service |
1d8f1c |
try {
|
|
Packit Service |
1d8f1c |
if (!GLib.Process.spawn_sync(null,
|
|
Packit Service |
1d8f1c |
args,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
GLib.SpawnFlags.SEARCH_PATH,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
out standard_error,
|
|
Packit Service |
1d8f1c |
out exit_status))
|
|
Packit Service |
1d8f1c |
warning("Switch xkb layout to %s failed.",
|
|
Packit Service |
1d8f1c |
engine.get_layout());
|
|
Packit Service |
1d8f1c |
} catch (GLib.SpawnError e) {
|
|
Packit Service |
1d8f1c |
warning("Execute setxkbmap failed: %s", e.message);
|
|
Packit Service |
1d8f1c |
return;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (exit_status != 0)
|
|
Packit Service |
1d8f1c |
warning("Execute setxkbmap failed: %s",
|
|
Packit Service |
1d8f1c |
standard_error ?? "(null)");
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
run_xmodmap();
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
public void run_xmodmap() {
|
|
Packit Service |
1d8f1c |
if (!m_use_xmodmap) {
|
|
Packit Service |
1d8f1c |
return;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
string homedir = GLib.Environment.get_home_dir();
|
|
Packit Service |
1d8f1c |
foreach (string xmodmap_file in XMODMAP_KNOWN_FILES) {
|
|
Packit Service |
1d8f1c |
string xmodmap_filepath = GLib.Path.build_filename(homedir,
|
|
Packit Service |
1d8f1c |
xmodmap_file);
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
if (!GLib.FileUtils.test(xmodmap_filepath, GLib.FileTest.EXISTS)) {
|
|
Packit Service |
1d8f1c |
continue;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
string[] args = {XMODMAP_COMMAND, xmodmap_filepath};
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
/* Call async here because if both setxkbmap and xmodmap is
|
|
Packit Service |
1d8f1c |
* sync, it seems a DBus timeout happens and xmodmap causes
|
|
Packit Service |
1d8f1c |
* a loop for a while and users would think panel icon is
|
|
Packit Service |
1d8f1c |
* frozen in case the global engine mode is disabled.
|
|
Packit Service |
1d8f1c |
*
|
|
Packit Service |
1d8f1c |
* Do not return here even if the previous async is running
|
|
Packit Service |
1d8f1c |
* so that all xmodmap can be done after setxkbmap is called.
|
|
Packit Service |
1d8f1c |
*/
|
|
Packit Service |
1d8f1c |
try {
|
|
Packit Service |
1d8f1c |
GLib.Process.spawn_async(null,
|
|
Packit Service |
1d8f1c |
args,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
GLib.SpawnFlags.SEARCH_PATH,
|
|
Packit Service |
1d8f1c |
null,
|
|
Packit Service |
1d8f1c |
null);
|
|
Packit Service |
1d8f1c |
} catch (GLib.SpawnError e) {
|
|
Packit Service |
1d8f1c |
warning("Execute xmodmap is failed: %s\n", e.message);
|
|
Packit Service |
1d8f1c |
return;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
break;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
|
|
Packit Service |
1d8f1c |
public void set_use_xmodmap(bool use_xmodmap) {
|
|
Packit Service |
1d8f1c |
m_use_xmodmap = use_xmodmap;
|
|
Packit Service |
1d8f1c |
}
|
|
Packit Service |
1d8f1c |
}
|