mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-14 01:47:30 +00:00
Merge pull request #2566 from keymanapp/linux-options-dconf
feat(linux): Keyboard options configuration dialog
This commit is contained in:
commit
8f73f5ec6c
13 changed files with 528 additions and 37 deletions
7
linux/.editorconfig
Normal file
7
linux/.editorconfig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
|
||||
[*.py]
|
||||
trim_trailing_whitespace = true
|
||||
intent_stype = space
|
||||
intent_size = 4
|
||||
|
||||
|
|
@ -13,6 +13,9 @@
|
|||
* Work on Linux packaging (#2263, #2290, #2320, #2321, #2325, #2474, #2515, #2551)
|
||||
|
||||
## 2019-09-19 12.0.18 beta
|
||||
* New Feature:
|
||||
* Add ability to set keyboard options from options.htm dialog (#2566)
|
||||
|
||||
* Bug Fix:
|
||||
* Extract icon from kmx instead of downloading it (#2075)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
/*
|
||||
* Keyman Input Method for IBUS (The Input Bus)
|
||||
*
|
||||
* Copyright (C) 2009-2018 SIL International
|
||||
* Copyright (C) 2009-2020 SIL International
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gio/gio.h>
|
||||
#include <keyman/keyboardprocessor.h>
|
||||
|
||||
#include "keymanutil.h"
|
||||
|
|
@ -325,7 +326,14 @@ ibus_keyman_engine_constructor (GType type,
|
|||
}
|
||||
g_free(kmx_file);
|
||||
|
||||
km_kbp_option_item *keyboard_opts = g_new0(km_kbp_option_item, 4);
|
||||
// Retrieve keyboard options from DConf
|
||||
// TODO: May need unique packageID and keyboard ID
|
||||
g_message("Loading options for kb_name: %s", keyman->kb_name);
|
||||
GQueue *queue_options = keyman_get_options_queue_fromdconf(keyman->kb_name, keyman->kb_name);
|
||||
int num_options = g_queue_get_length(queue_options);
|
||||
|
||||
// Allocate enough options for: 3 environments plus num_options plus 1 pad struct of 0's
|
||||
km_kbp_option_item *keyboard_opts = g_new0(km_kbp_option_item, KEYMAN_ENVIRONMENT_OPTIONS + num_options + 1);
|
||||
|
||||
keyboard_opts[0].scope = KM_KBP_OPT_ENVIRONMENT;
|
||||
km_kbp_cp *cp = g_utf8_to_utf16 ("platform", -1, NULL, NULL, NULL);
|
||||
|
|
@ -371,7 +379,13 @@ ibus_keyman_engine_constructor (GType type,
|
|||
// g_free(lang);
|
||||
keyboard_opts[2].value = cp;
|
||||
|
||||
// keyboard_opts[3] already initialised to {0, 0, 0}
|
||||
// If queue_options contains keyboard options, pop them into keyboard_opts[3] onward
|
||||
for(int i=0; i<num_options; i++)
|
||||
{
|
||||
memmove(&(keyboard_opts[KEYMAN_ENVIRONMENT_OPTIONS+i]), g_queue_pop_head(queue_options), sizeof(km_kbp_option_item));
|
||||
}
|
||||
|
||||
// keyboard_opts[tail] already initialised to {0, 0, 0}
|
||||
|
||||
km_kbp_status status_keyboard = km_kbp_keyboard_load(abs_kmx_path, &(keyman->keyboard));
|
||||
g_free(abs_kmx_path);
|
||||
|
|
@ -388,10 +402,11 @@ ibus_keyman_engine_constructor (GType type,
|
|||
{
|
||||
g_warning("problem creating km_kbp_state");
|
||||
}
|
||||
for (int i =0; i < 3; i++) {
|
||||
for (int i=0; i < KEYMAN_ENVIRONMENT_OPTIONS + num_options + 1; i++) {
|
||||
g_free((km_kbp_cp *)keyboard_opts[i].key);
|
||||
g_free((km_kbp_cp *)keyboard_opts[i].value);
|
||||
}
|
||||
g_queue_free_full(queue_options, NULL);
|
||||
g_free(keyboard_opts);
|
||||
|
||||
reset_context(engine);
|
||||
|
|
@ -793,6 +808,29 @@ ibus_keyman_engine_process_key_event (IBusEngine *engine,
|
|||
break;
|
||||
case KM_KBP_IT_PERSIST_OPT:
|
||||
g_message("PERSIST_OPT action %d/%d", i+1, (int)num_action_items);
|
||||
// Save keyboard option
|
||||
if (action_items[i].option != NULL)
|
||||
{
|
||||
// Allocate for 1 option plus 1 pad struct of 0's
|
||||
km_kbp_option_item *keyboard_opts = g_new0(km_kbp_option_item, 2);
|
||||
memmove(&(keyboard_opts[0]), action_items[i].option, sizeof(km_kbp_option_item));
|
||||
event_status = km_kbp_state_options_update(keyman->state, keyboard_opts);
|
||||
if (event_status != KM_KBP_STATUS_OK)
|
||||
{
|
||||
g_warning("problem saving option for km_kbp_keyboard");
|
||||
}
|
||||
g_free(keyboard_opts);
|
||||
|
||||
// Put the keyboard option into DConf
|
||||
if (action_items[i].option != NULL && action_items[i].option->key != NULL &&
|
||||
action_items[i].option->value != NULL)
|
||||
{
|
||||
g_message("Saving keyboard option to DConf");
|
||||
// Load the current keyboard options from DConf
|
||||
keyman_put_options_todconf(keyman->kb_name, keyman->kb_name,
|
||||
action_items[i].option->key, action_items[i].option->value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KM_KBP_IT_EMIT_KEYSTROKE:
|
||||
if (keyman->char_buffer != NULL)
|
||||
|
|
@ -976,3 +1014,4 @@ ibus_keyman_engine_property_activate (IBusEngine *engine,
|
|||
parent_class->property_activate (engine, prop_name, prop_state);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <keyman/keyboardprocessor.h>
|
||||
|
||||
#include "keymanutil.h"
|
||||
#include "kmpdetails.h"
|
||||
|
|
@ -300,6 +300,154 @@ ibus_keyman_get_component (void)
|
|||
return component;
|
||||
}
|
||||
|
||||
|
||||
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
|
||||
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
|
||||
//
|
||||
// Parameters:
|
||||
// package_id (gchar *): Package ID
|
||||
// keyboard_id (gchar *): Keyboard ID
|
||||
//
|
||||
// Returns a newly allocated gchar**; free with g_strfreev()
|
||||
gchar**
|
||||
keyman_get_options_fromdconf(gchar *package_id,
|
||||
gchar *keyboard_id)
|
||||
{
|
||||
g_message("keyman_get_options_fromdconf");
|
||||
|
||||
// Obtain keyboard options from DConf
|
||||
gchar *path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_PATH, package_id, keyboard_id);
|
||||
GSettings *child_settings = g_settings_new_with_path(KEYMAN_CHILD_DCONF_NAME, path);
|
||||
gchar **options = NULL;
|
||||
if (child_settings != NULL)
|
||||
{
|
||||
options = g_settings_get_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY);
|
||||
}
|
||||
|
||||
g_object_unref(G_OBJECT(child_settings));
|
||||
g_free(path);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
|
||||
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
|
||||
//
|
||||
// Parameters:
|
||||
// package_id (gchar *): Package ID
|
||||
// keyboard_id (gchar *): Keyboard ID
|
||||
//
|
||||
// Return a newly allocated GQueue; free with g_queue_free_full()
|
||||
GQueue*
|
||||
keyman_get_options_queue_fromdconf(gchar *package_id,
|
||||
gchar *keyboard_id)
|
||||
{
|
||||
g_message("keyman_get_options_queue_fromdconf");
|
||||
GQueue *queue_options = g_queue_new();
|
||||
|
||||
// Obtain keyboard options from DConf
|
||||
gchar **options = keyman_get_options_fromdconf(package_id, keyboard_id);
|
||||
|
||||
// Parse options into queue_options
|
||||
if (*options != NULL)
|
||||
{
|
||||
int index = 0;
|
||||
while (options[index] != NULL)
|
||||
{
|
||||
gchar **option_tokens = g_strsplit(options[index], "=", 2);
|
||||
if (option_tokens != NULL && option_tokens[0] != NULL && option_tokens[1] != NULL)
|
||||
{
|
||||
g_message("Keyboard Option [%d], %s=%s", index, option_tokens[0], option_tokens[1]);
|
||||
km_kbp_option_item *opt = g_new0(km_kbp_option_item, 1);
|
||||
opt[0].scope = KM_KBP_OPT_KEYBOARD;
|
||||
km_kbp_cp *ocp = g_utf8_to_utf16(option_tokens[0], -1, NULL, NULL, NULL);
|
||||
opt[0].key = ocp;
|
||||
ocp = g_utf8_to_utf16 (option_tokens[1], -1, NULL, NULL, NULL);
|
||||
opt[0].value = ocp;
|
||||
g_queue_push_tail(queue_options, opt);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
return queue_options;
|
||||
}
|
||||
|
||||
// Write new keyboard option to DConf.
|
||||
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
|
||||
// If the option key already exists, the value is updated. Otherwise a new string 'option_key=option_value' is appended.
|
||||
//
|
||||
// Parameters:
|
||||
// package_id (gchar *): Package ID
|
||||
// keyboard_id (gchar *): Keyboard ID
|
||||
// option_key (gchar *): Key for the new option
|
||||
// option_value (gchar *): Value of the new option
|
||||
void
|
||||
keyman_put_options_todconf(gchar *package_id,
|
||||
gchar *keyboard_id,
|
||||
gchar *option_key,
|
||||
gchar *option_value)
|
||||
{
|
||||
g_message("keyman_put_options_todconf");
|
||||
if (package_id == NULL || keyboard_id == NULL || option_key == NULL || option_value == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtain keyboard options from DConf
|
||||
gchar **options = keyman_get_options_fromdconf(package_id, keyboard_id);
|
||||
gchar *needle = g_strdup_printf("%s=", option_key);
|
||||
gchar *kvp = g_strdup_printf("%s=%s", option_key, option_value);
|
||||
|
||||
if (*options != NULL)
|
||||
{
|
||||
int index = 0;
|
||||
gboolean option_updated = FALSE;
|
||||
while (options[index] != NULL)
|
||||
{
|
||||
// If option_key already exists, update value with option_value
|
||||
if (g_strrstr(options[index], needle) != NULL)
|
||||
{
|
||||
options[index] = kvp;
|
||||
option_updated = TRUE;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!option_updated)
|
||||
{
|
||||
// Resize to add new option and null-terminate
|
||||
options = g_realloc(options, strlen(kvp) + 1);
|
||||
options[index] = kvp;
|
||||
options[index+1] = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If options don't exist, allocate space for new option and null-terminate
|
||||
options = g_malloc(strlen(kvp) + 1);
|
||||
options[0] = kvp;
|
||||
options[1] = NULL;
|
||||
}
|
||||
|
||||
// Write to DConf
|
||||
gchar *path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_PATH, package_id, keyboard_id);
|
||||
GSettings *child_settings = g_settings_new_with_path(KEYMAN_CHILD_DCONF_NAME, path);
|
||||
if (child_settings != NULL)
|
||||
{
|
||||
g_message("writing keyboard options to DConf");
|
||||
g_settings_set_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY, options);
|
||||
}
|
||||
|
||||
g_object_unref(G_OBJECT(child_settings));
|
||||
g_free(path);
|
||||
g_free(kvp);
|
||||
g_free(needle);
|
||||
g_free(options);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <locale.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
/*
|
||||
* Keyman Input Method for IBUS (The Input Bus)
|
||||
*
|
||||
* Copyright (C) 2018 SIL International
|
||||
* Copyright (C) 2018, 2020 SIL International
|
||||
*
|
||||
* kmflutil is dual licensed under the MIT or GPL licenses as described below.
|
||||
*
|
||||
|
|
@ -53,9 +53,60 @@
|
|||
#define __KEYMANUTIL_H__
|
||||
|
||||
#include <ibus.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include <keyman/keyboardprocessor.h>
|
||||
|
||||
// Number of default Keyboard processor environment options for: "platform", "baseLayout", and "baseLayoutAlt"
|
||||
#define KEYMAN_ENVIRONMENT_OPTIONS 3
|
||||
|
||||
// Path information for Keyman keyboard options in DConf
|
||||
#define KEYMAN_DCONF_NAME "com.keyman.options"
|
||||
#define KEYMAN_CHILD_DCONF_NAME "com.keyman.options.child"
|
||||
#define KEYMAN_DCONF_PATH "/desktop/ibus/keyman/options/"
|
||||
#define KEYMAN_DCONF_OPTIONS_KEY "options"
|
||||
|
||||
void ibus_keyman_init (void);
|
||||
GList *ibus_keyman_list_engines (void);
|
||||
IBusComponent *ibus_keyman_get_component (void);
|
||||
|
||||
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
|
||||
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
|
||||
//
|
||||
// Parameters:
|
||||
// package_id (gchar *): Package ID
|
||||
// keyboard_id (gchar *): Keyboard ID
|
||||
//
|
||||
// Returns a newly allocated gchar**; free with g_strfreev()
|
||||
gchar** keyman_get_options_fromdconf
|
||||
(gchar *package_id,
|
||||
gchar *keyboard_id);
|
||||
|
||||
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
|
||||
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
|
||||
//
|
||||
// Parameters:
|
||||
// package_id (gchar *): Package ID
|
||||
// keyboard_id (gchar *): Keyboard ID
|
||||
//
|
||||
// Return a newly allocated GQueue; free with g_queue_free_full()
|
||||
GQueue* keyman_get_options_queue_fromdconf
|
||||
(gchar *package_id,
|
||||
gchar *keyboard_id);
|
||||
|
||||
// Write new keyboard option to DConf.
|
||||
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
|
||||
// If the option key already exists, the value is updated. Otherwise a new string 'option_key=option_value' is appended.
|
||||
//
|
||||
// Parameters:
|
||||
// package_id (gchar *): Package ID
|
||||
// keyboard_id (gchar *): Keyboard ID
|
||||
// option_key (gchar *): Key for the new option
|
||||
// option_value (gchar *): Value of the new option
|
||||
void keyman_put_options_todconf
|
||||
(gchar *package_id,
|
||||
gchar *keyboard_id,
|
||||
gchar *option_key,
|
||||
gchar *option_value);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ install-temp:
|
|||
mkdir -p /tmp/kmfl/`python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)'`
|
||||
PYTHONUSERBASE=/tmp/kmfl python3 setup.py install --user
|
||||
|
||||
uninstall: # run as sudo
|
||||
uninstall: clean # run as sudo
|
||||
rm -rf /usr/local/share/keyman/icons
|
||||
rm -f /usr/local/share/man/man1/km-*.1
|
||||
pip3 uninstall keyman_config
|
||||
|
|
|
|||
|
|
@ -10,9 +10,16 @@ python3-requests-cache python3 python3-gi gir1.2-webkit-3.0 dconf-cli python3-se
|
|||
|
||||
You will also need kmflcomp either from a package or built and installed locally.
|
||||
|
||||
run the script `./createkeymandirs.sh` to create the directories for these programs to
|
||||
Run the script `./createkeymandirs.sh` to create the directories for these programs to
|
||||
install the packages to
|
||||
|
||||
Also copy and compile the GSettings schema
|
||||
```bash
|
||||
cd keyman_config
|
||||
sudo cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas
|
||||
sudo glib-compile-schemas /usr/share/glib-2.0/schemas
|
||||
```
|
||||
|
||||
### Installing manually from the repo
|
||||
|
||||
`make && sudo make install` will install locally to /usr/local
|
||||
|
|
@ -32,6 +39,7 @@ This displays a configuration panel that shows the currently installed Keyman ke
|
|||
* `Uninstall` - uninstall selected keyboard
|
||||
* `About` - show information about selected keyboard
|
||||
* `Help` - display help documentation about selected keyboard
|
||||
* `Options` - display options.htm form for setting keyboard options
|
||||
-----------------------------------
|
||||
|
||||
* `Refresh` - useful if you install or uninstall on the commandline while running km-config.
|
||||
|
|
@ -43,12 +51,9 @@ This displays a configuration panel that shows the currently installed Keyman ke
|
|||
|
||||
This uses the keyman.com website to install kmps.
|
||||
|
||||
The website doesn't know about linux yet (until after 10.0 release) so
|
||||
pretending to be a mac for now.
|
||||
|
||||
Search for a language or keyboard in the search box
|
||||
Select a keyboard from the list
|
||||
In 'Downloads for your device' there will be a 'Install keyboard' button for the keyboard for macOS
|
||||
Search for a language or keyboard in the search box.
|
||||
Select a keyboard from the list.
|
||||
In 'Downloads for your device' there will be an 'Install keyboard' button for the keyboard for Linux.
|
||||
Click it to download the keyboard and bring up the `InstallKmpWindow` for more details and to confirm installing.
|
||||
|
||||
Secondary-click gives you a menu including 'Back' to go back a page.
|
||||
|
|
|
|||
15
linux/keyman-config/com.keyman.gschema.xml
Normal file
15
linux/keyman-config/com.keyman.gschema.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<schemalist>
|
||||
<schema id="com.keyman.options" path="/desktop/ibus/keyman/options/">
|
||||
|
||||
<child name="keyboard-options" schema="com.keyman.options.child"/>
|
||||
|
||||
</schema>
|
||||
|
||||
<schema id="com.keyman.options.child">
|
||||
<key name="options" type="as">
|
||||
<default>[]</default>
|
||||
<summary>keyboard options.htm settings</summary>
|
||||
<description>List of strings</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
73
linux/keyman-config/keyman_config/dconf_util.py
Normal file
73
linux/keyman-config/keyman_config/dconf_util.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import logging
|
||||
from gi.repository import Gio, Gtk
|
||||
|
||||
# DConf path destkop/ibus/keyman/options
|
||||
DCONF_BASE = "com.keyman.options"
|
||||
|
||||
# Utilities to get and set Keyman options in DConf:
|
||||
# /desktop/ibus/keyman/options/packageID/keyboardID/options
|
||||
|
||||
|
||||
def get_child_schema(info):
|
||||
settings = Gio.Settings.new(DCONF_BASE)
|
||||
path = settings.get_property('path')
|
||||
if not path.endswith('/'):
|
||||
path += '/'
|
||||
path += info['packageID'] + '/' + info['keyboardID'] + '/'
|
||||
return Gio.Settings(DCONF_BASE + '.child', path)
|
||||
|
||||
|
||||
def get_option(info):
|
||||
"""
|
||||
Get the Keyman keyboard options from DConf
|
||||
Convert from list of comma-separated strings into dictionary
|
||||
|
||||
Args:
|
||||
info: dictionary
|
||||
packageID (str): Package ID
|
||||
keyboardID(str): Keyboard ID
|
||||
|
||||
Returns:
|
||||
result (dictionary): Keyboard options
|
||||
"""
|
||||
result = {}
|
||||
if "packageID" in info and "keyboardID" in info:
|
||||
child_schema = get_child_schema(info)
|
||||
list_options = child_schema.get_strv("options")
|
||||
result = dict(option.split("=") for option in list_options)
|
||||
return result
|
||||
|
||||
|
||||
def set_option(info, options):
|
||||
"""
|
||||
Store the Keyman keyboard options in DConf as a list of strings
|
||||
|
||||
Args:
|
||||
info: dictionary
|
||||
packageID (str): package ID
|
||||
keyboardID (str): keyboard ID
|
||||
options: dictionary
|
||||
key and values to store
|
||||
"""
|
||||
if "packageID" in info and "keyboardID" in info and options:
|
||||
# Convert dictionary of options into a list of comma-separated option strings
|
||||
list_options = []
|
||||
for key, value in options.items():
|
||||
list_options.append(key+"="+value)
|
||||
|
||||
child_schema = get_child_schema(info)
|
||||
child_schema.set_strv("options", list_options)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
info = {"packageID": "invalid", "keyboardID": "invalid"}
|
||||
options = get_option(info)
|
||||
assert(options == {})
|
||||
|
||||
info = {"packageID": "sil_cipher_music", "keyboardID": "sil_cipher_music"}
|
||||
options = get_option(info)
|
||||
|
||||
options["set_nfc"] = "1"
|
||||
set_option(info, options)
|
||||
|
|
@ -15,6 +15,32 @@ class InstallArea(GObject.GEnum):
|
|||
IA_USER = 3
|
||||
IA_UNKNOWN = 99
|
||||
|
||||
|
||||
def get_install_area_path(area):
|
||||
"""
|
||||
Get the path of an install area.
|
||||
|
||||
Args:
|
||||
area (InstallArea): install area to check
|
||||
InstallArea.IA_USER: ~/.local/share/keyman
|
||||
InstallArea.IA_SHARED: /usr/local/share/keyman
|
||||
InstallArea.IA_OS: /usr/share/keyman
|
||||
InstallArea.IA_UNKNOWN: /usr/share/keyman
|
||||
|
||||
Returns:
|
||||
string: path of the install area
|
||||
"""
|
||||
check_path = "/usr/share/keyman"
|
||||
if area == InstallArea.IA_USER:
|
||||
check_path = user_keyman_dir()
|
||||
elif area == InstallArea.IA_SHARED:
|
||||
check_path = "/usr/local/share/keyman"
|
||||
elif area == InstallArea.IA_OS:
|
||||
check_path = "/usr/share/keyman"
|
||||
|
||||
return check_path
|
||||
|
||||
|
||||
def get_installed_kmp(area):
|
||||
"""
|
||||
Get list of installed kmp in an install area.
|
||||
|
|
@ -35,13 +61,7 @@ def get_installed_kmp(area):
|
|||
path (str): base path where keyboard is installed
|
||||
description (str): Keyboard description
|
||||
"""
|
||||
check_paths = []
|
||||
if area == InstallArea.IA_USER:
|
||||
check_paths = [ user_keyman_dir() ]
|
||||
elif area == InstallArea.IA_SHARED:
|
||||
check_paths = [ "/usr/local/share/keyman" ]
|
||||
elif area == InstallArea.IA_OS:
|
||||
check_paths = [ "/usr/share/keyman" ]
|
||||
check_paths = [ get_install_area_path(area) ]
|
||||
|
||||
return get_installed_kmp_paths(check_paths)
|
||||
|
||||
|
|
@ -57,12 +77,15 @@ def get_installed_kmp_paths(check_paths):
|
|||
list: Installed kmp
|
||||
dict: Keyboard
|
||||
packageID (str): kmp ID
|
||||
keyboardID (str): Keyboard ID
|
||||
name (str): Keyboard name
|
||||
kmpname (str): Keyboard name in local
|
||||
version (str): Keyboard version
|
||||
kmpversion (str):
|
||||
path (str): base path of area where kmp is installed
|
||||
areapath (str): base path of area where kmp is installed
|
||||
description (str): Keyboard description
|
||||
has_kbjson (bool): Keyboard is in the json file
|
||||
has_kboptions (bool): Keyboard uses options.htm form
|
||||
"""
|
||||
installed_keyboards = {}
|
||||
for keymanpath in check_paths:
|
||||
|
|
@ -96,7 +119,15 @@ def get_installed_kmp_paths(check_paths):
|
|||
version = md_version
|
||||
name = md_name
|
||||
|
||||
installed_keyboards[o] = { "packageID" : o, "keyboardID" : keyboardID, "name" : name, "kmpname" : md_name, "version" : version, "kmpversion" : md_version, "areapath" : keymanpath, "description" : description, "has_kbjson" : has_kbjson}
|
||||
has_kboptions = False
|
||||
if files:
|
||||
for fileinfo in files:
|
||||
if fileinfo['name'] == "options.htm":
|
||||
has_kboptions = True
|
||||
break
|
||||
installed_keyboards[o] = {"packageID" : o, "keyboardID" : keyboardID, "name" : name, "kmpname" : md_name,
|
||||
"version" : version, "kmpversion" : md_version, "areapath" : keymanpath,
|
||||
"description" : description, "has_kbjson" : has_kbjson, "has_kboptions" : has_kboptions}
|
||||
return installed_keyboards
|
||||
|
||||
|
||||
|
|
@ -117,7 +148,7 @@ def get_kmp_version(packageID):
|
|||
os_kmp = get_installed_kmp(InstallArea.IA_OS)
|
||||
|
||||
if packageID in os_kmp:
|
||||
version = os_kmp[keyboardid]['version']
|
||||
version = os_kmp[packageID]['version']
|
||||
|
||||
if packageID in shared_kmp:
|
||||
shared_version = shared_kmp[packageID]['version']
|
||||
|
|
@ -148,7 +179,7 @@ def get_kmp_version_user(packageID):
|
|||
str: kmp version if kmp ID is installed
|
||||
None: if not found
|
||||
"""
|
||||
user_kmp = get_installed_kmp_user()
|
||||
user_kmp = get_installed_kmp(InstallArea.IA_USER)
|
||||
if packageID in user_kmp:
|
||||
return user_kmp[packageID]['version']
|
||||
else:
|
||||
|
|
|
|||
86
linux/keyman-config/keyman_config/options.py
Normal file
86
linux/keyman-config/keyman_config/options.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import ast
|
||||
import gi
|
||||
import logging
|
||||
import webbrowser
|
||||
import urllib.parse
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('WebKit2', '4.0')
|
||||
from gi.repository import Gtk, WebKit2
|
||||
from urllib.parse import parse_qsl, urlencode
|
||||
from keyman_config.accelerators import bind_accelerator, init_accel
|
||||
from keyman_config.dconf_util import get_option, set_option
|
||||
|
||||
|
||||
class OptionsView(Gtk.Window):
|
||||
|
||||
def __init__(self, info):
|
||||
self.accelerators = None
|
||||
self.optionurl = info["optionurl"]
|
||||
self.packageID = info["packageID"]
|
||||
self.keyboardID = info["keyboardID"]
|
||||
kbtitle = self.packageID + " Settings"
|
||||
Gtk.Window.__init__(self, title=kbtitle)
|
||||
init_accel(self)
|
||||
|
||||
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||
|
||||
# Keyman Desktop gets current option settings from the registry.
|
||||
# Similarly, we'll read Keyman options from DConf and update optionurl
|
||||
info = {"packageID": self.packageID, "keyboardID": self.keyboardID}
|
||||
self.options = get_option(info)
|
||||
params = ""
|
||||
|
||||
if self.options:
|
||||
# Convert dictionary to query
|
||||
params = "?" + urlencode(self.options)
|
||||
|
||||
s = Gtk.ScrolledWindow()
|
||||
self.webview = WebKit2.WebView()
|
||||
self.webview.connect("decide-policy", self.doc_policy)
|
||||
self.webview.load_uri(self.optionurl + params)
|
||||
s.add(self.webview)
|
||||
vbox.pack_start(s, True, True, 0)
|
||||
|
||||
hbox = Gtk.Box(spacing=12)
|
||||
vbox.pack_start(hbox, False, False, 6)
|
||||
|
||||
self.add(vbox)
|
||||
|
||||
def doc_policy(self, web_view, decision, decision_type):
|
||||
logging.info("Checking policy")
|
||||
logging.debug("received policy decision request of type: {0}".format(decision_type.value_name))
|
||||
if decision_type == WebKit2.PolicyDecisionType.NAVIGATION_ACTION or \
|
||||
decision_type == WebKit2.PolicyDecisionType.NEW_WINDOW_ACTION:
|
||||
nav_action = decision.get_navigation_action()
|
||||
request = nav_action.get_request()
|
||||
uri = request.get_uri()
|
||||
logging.debug("nav request is for uri %s", uri)
|
||||
parsed = urllib.parse.urlparse(uri)
|
||||
if parsed.scheme == "keyman":
|
||||
logging.debug("using keyman scheme")
|
||||
if parsed.path == "cancel":
|
||||
pass
|
||||
elif parsed.path == "ok":
|
||||
logging.debug("submit options form")
|
||||
# Parse the response for the option_key value and merge the updates
|
||||
if parsed.query:
|
||||
updated_options = parse_qsl(parsed.query, keep_blank_values=True)
|
||||
self.options.update(updated_options)
|
||||
self.process_option()
|
||||
|
||||
self.close()
|
||||
return True
|
||||
|
||||
if not "options.htm" in uri:
|
||||
logging.debug("opening uri %s in webbrowser")
|
||||
webbrowser.open(uri)
|
||||
decision.ignore()
|
||||
return True
|
||||
return False
|
||||
|
||||
def process_option(self):
|
||||
# Write the Keyman options to DConf
|
||||
info = { "packageID": self.packageID, "keyboardID": self.keyboardID}
|
||||
set_option(info, self.options)
|
||||
|
|
@ -9,8 +9,9 @@ gi.require_version('Gtk', '3.0')
|
|||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk, Gdk, GdkPixbuf, GObject
|
||||
|
||||
from keyman_config.list_installed_kmp import get_installed_kmp, InstallArea
|
||||
from keyman_config.list_installed_kmp import get_install_area_path, get_installed_kmp, InstallArea
|
||||
from keyman_config.welcome import WelcomeView
|
||||
from keyman_config.options import OptionsView
|
||||
from keyman_config.keyboard_details import KeyboardDetailsView
|
||||
from keyman_config.downloadkeyboard import DownloadKmpWindow
|
||||
from keyman_config.install_window import InstallKmpWindow, find_keyman_image
|
||||
|
|
@ -68,7 +69,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
# window is split left/right hbox
|
||||
# right is ButtonBox
|
||||
# possibly 2 ButtonBox in a vbox
|
||||
# top one with _Remove, _About, ?_Welcome? or ?Read_Me?
|
||||
# top one with _Remove, _About, ?_Welcome? or ?Read_Me?, _Options
|
||||
# bottom one with _Download, _Install, Re_fresh, _Close
|
||||
# left is GtkTreeView - does it need to be inside anything else apart from the hbox?
|
||||
# with liststore which defines columns
|
||||
|
|
@ -91,7 +92,8 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
str, # version
|
||||
str, # packageID
|
||||
int, # enum InstallArea (KmpArea is GObject version)
|
||||
str) # path to welcome file if it exists or None
|
||||
str, # path to welcome file if it exists or None
|
||||
str) # path to options file if it exists or None
|
||||
|
||||
# add installed keyboards to the the store e.g.
|
||||
# treeiter = store.append([GdkPixbuf.Pixbuf.new_from_file_at_size("/usr/local/share/keyman/libtralo/libtralo.ico.png", 16, 16), \
|
||||
|
|
@ -136,6 +138,12 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
self.help_button.connect("clicked", self.on_help_clicked)
|
||||
bbox_top.add(self.help_button)
|
||||
|
||||
self.options_button = Gtk.Button.new_with_mnemonic("_Options")
|
||||
self.options_button.set_tooltip_text("Settings for keyboard")
|
||||
self.options_button.connect("clicked", self.on_options_clicked)
|
||||
self.options_button.set_sensitive(False)
|
||||
bbox_top.add(self.options_button)
|
||||
|
||||
vbox.pack_start(bbox_top, False, False, 12)
|
||||
|
||||
|
||||
|
|
@ -176,16 +184,19 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
|
||||
if install_area == InstallArea.IA_USER:
|
||||
welcome_file = os.path.join(user_keyboard_dir(kmpdata['packageID']), "welcome.htm")
|
||||
options_file = os.path.join(user_keyboard_dir(kmpdata['packageID']), "options.htm")
|
||||
icofile = os.path.join(user_keyboard_dir(kmpdata['packageID']), kmpdata['packageID'] + bmppng)
|
||||
if not os.path.isfile(icofile):
|
||||
icofile = os.path.join(user_keyboard_dir(kmpdata['packageID']), kmpdata['keyboardID'] + bmppng)
|
||||
elif install_area == InstallArea.IA_SHARED:
|
||||
welcome_file = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], "welcome.htm")
|
||||
options_file = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], "options.htm")
|
||||
icofile = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], kmpdata['packageID'] + bmppng)
|
||||
if not os.path.isfile(icofile):
|
||||
icofile = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], kmpdata['keyboardID'] + bmppng)
|
||||
else:
|
||||
welcome_file = os.path.join("/usr/share/keyman", kmpdata['packageID'], "welcome.htm")
|
||||
options_file = os.path.join("/usr/share/keyman", kmpdata['packageID'], "options.htm")
|
||||
icofile = os.path.join("/usr/share/keyman", kmpdata['packageID'], kmpdata['packageID'] + bmppng)
|
||||
if not os.path.isfile(icofile):
|
||||
icofile = os.path.join("/usr/share/keyman", kmpdata['packageID'], kmpdata['keyboardID'] + bmppng)
|
||||
|
|
@ -194,13 +205,15 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
|
||||
if not os.path.isfile(welcome_file):
|
||||
welcome_file = None
|
||||
|
||||
if not os.path.isfile(options_file):
|
||||
options_file = None
|
||||
treeiter = store.append([GdkPixbuf.Pixbuf.new_from_file_at_size(icofile, 16, 16), \
|
||||
kmpdata['name'], \
|
||||
kmpdata['version'], \
|
||||
kmpdata['packageID'], \
|
||||
install_area, \
|
||||
welcome_file])
|
||||
welcome_file, \
|
||||
options_file])
|
||||
|
||||
def refresh_installed_kmp(self):
|
||||
logging.debug("Refreshing listview")
|
||||
|
|
@ -225,13 +238,13 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
self.incomplete_kmp.append(kmpdata)
|
||||
self.addlistitems(os_kmp, self.store, InstallArea.IA_OS)
|
||||
|
||||
|
||||
def on_tree_selection_changed(self, selection):
|
||||
model, treeiter = selection.get_selected()
|
||||
if treeiter is not None:
|
||||
self.uninstall_button.set_tooltip_text("Uninstall keyboard package " + model[treeiter][1])
|
||||
self.help_button.set_tooltip_text("Help for keyboard package " + model[treeiter][1])
|
||||
self.about_button.set_tooltip_text("About keyboard package " + model[treeiter][1])
|
||||
self.options_button.set_tooltip_text("Settings for keyboard package " + model[treeiter][1])
|
||||
logging.debug("You selected %s version %s", model[treeiter][1], model[treeiter][2])
|
||||
if model[treeiter][4] == InstallArea.IA_USER:
|
||||
logging.debug("Enabling uninstall button for %s in %s", model[treeiter][3], model[treeiter][4])
|
||||
|
|
@ -239,10 +252,16 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
else:
|
||||
self.uninstall_button.set_sensitive(False)
|
||||
logging.debug("Disabling uninstall button for %s in %s ", model[treeiter][3], model[treeiter][4])
|
||||
# welcome file if it exists
|
||||
if model[treeiter][5]:
|
||||
self.help_button.set_sensitive(True)
|
||||
else:
|
||||
self.help_button.set_sensitive(False)
|
||||
# options file if it exists
|
||||
if model[treeiter][6]:
|
||||
self.options_button.set_sensitive(True)
|
||||
else:
|
||||
self.options_button.set_sensitive(False)
|
||||
|
||||
def on_help_clicked(self, button):
|
||||
model, treeiter = self.tree.get_selection().get_selected()
|
||||
|
|
@ -258,6 +277,22 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
else:
|
||||
logging.info("welcome.htm not available")
|
||||
|
||||
def on_options_clicked(self, button):
|
||||
model, treeiter = self.tree.get_selection().get_selected()
|
||||
if treeiter is not None:
|
||||
logging.info("Open options.htm for %s if available", model[treeiter][1])
|
||||
options_file = model[treeiter][6]
|
||||
if options_file and os.path.isfile(options_file):
|
||||
uri_path = pathlib.Path(options_file).as_uri()
|
||||
logging.info("opening" + uri_path)
|
||||
# TODO: Determine keyboardID
|
||||
info = { "optionurl": uri_path, "packageID": model[treeiter][3], "keyboardID": model[treeiter][3] }
|
||||
w = OptionsView(info)
|
||||
w.resize(800, 600)
|
||||
w.show_all()
|
||||
else:
|
||||
logging.info("options.htm not available")
|
||||
|
||||
def on_uninstall_clicked(self, button):
|
||||
model, treeiter = self.tree.get_selection().get_selected()
|
||||
if treeiter is not None:
|
||||
|
|
@ -281,12 +316,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
|
|||
model, treeiter = self.tree.get_selection().get_selected()
|
||||
if treeiter is not None:
|
||||
logging.info("Show keyboard details of " + model[treeiter][1])
|
||||
if model[treeiter][4] == InstallArea.IA_USER:
|
||||
areapath = user_keyman_dir()
|
||||
elif model[treeiter][4] == InstallArea.IA_SHARED:
|
||||
areapath = "/usr/local/share/keyman"
|
||||
else:
|
||||
areapath = "/usr/share/keyman"
|
||||
areapath = get_install_area_path(model[treeiter][4])
|
||||
kmp = { "name" : model[treeiter][1], "version" : model[treeiter][2], "packageID" : model[treeiter][3], "areapath" : areapath}
|
||||
w = KeyboardDetailsView(kmp)
|
||||
w.resize(800, 450)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ if [[ "${SUDOINSTALL}" == "yes" ]]; then
|
|||
echo "keyman-config must be built before it is installed. Run 'make configure' if needed then 'make'"
|
||||
exit 1
|
||||
fi
|
||||
echo "doing sudo glib-compile-schemas for keyman-config"
|
||||
cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas/
|
||||
glib-compile-schemas /usr/share/glib-2.0/schemas/
|
||||
echo "doing sudo install of keyman-config"
|
||||
make install
|
||||
elif [[ "${SUDOINSTALL}" == "uninstall" ]]; then
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue