diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d2863ef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+.vscode/
+ubl-settings-keyboard
+*~
+build/
+compile/
+*#
+terminal-commands/
+source/ubl-cmake.h
+vgcore*
+.BUILD.md
+.updatebuild.sh
+.install.sh
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..21263cf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,165 @@
+#!/usr/bin/make -f
+
+#SHELL := /bin/bash
+MAKEFILE_FILEPATH := $(abspath $(lastword $(MAKEFILE_LIST)))
+MAKEFILE_DIR := $(notdir $(patsubst %/,%,$(dir $(MAKEFILE_FILEPATH))))
+MAKEFILE_PATH := $(dir $(MAKEFILE_FILEPATH))
+
+CMAKE_COMMAND = cmake
+CMAKE_SOURCE_DIR = $(MAKEFILE_PATH)source
+CMAKE_BUILD_DIR = $(MAKEFILE_PATH)compile
+DEPENDS = /bin/cmake
+PREFIX ?= /usr/local
+PKGNAME = $(MAKEFILE_DIR)
+FILE_VER = source/${PKGNAME}.h
+
+default_target: all
+
+.PHONY: all init depend debug prepare check build uninstall install clean help
+
+all: init build
+
+init:
+ @echo "Initialize ..."; \
+ if [[ -d ".git" ]]; then \
+ LATEST_TAG=$$(git describe --abbrev=0 --tags | sed 's/^v//'); \
+ if [[ -z "$${LATEST_TAG}" ]]; \
+ then \
+ LATEST_TAG=$$"0.0"; \
+ echo "$${LATEST_TAG} is empty"; \
+ fi; \
+ else \
+ LATEST_TAG="Development"; \
+ fi; \
+ sed -r "s/^(string version_application).*/\1 = \"$${LATEST_TAG}\";/" -i ${FILE_VER}; \
+ echo "-- Build path: ${CMAKE_BUILD_DIR}"
+
+depend:
+ @echo "Check depends ..."
+ @for FILE_DEPEND in $(DEPENDS); do \
+ if [[ ! -f "$${FILE_DEPEND}" ]]; then \
+ echo "ERROR: Depend '$${FILE_DEPEND}' not found !"; \
+ exit 1; \
+ fi; \
+ done; \
+ $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B${CMAKE_BUILD_DIR} --check-build-system CMakeFiles/Makefile.cmake 1 || exit 1; \
+ echo "Check depends: OK"
+
+debug:
+ @echo "Debug ..."
+ if [[ ! -d "${CMAKE_BUILD_DIR}" ]]; then \
+ $(CMAKE_COMMAND) -S${CMAKE_SOURCE_DIR} -B${CMAKE_BUILD_DIR} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="${PREFIX}"; \
+ fi; \
+ echo "Debug: OK"
+
+prepare:
+ @echo "Prepare ..."; \
+ if [[ ! -d "${CMAKE_BUILD_DIR}" ]]; then \
+ $(CMAKE_COMMAND) -S${CMAKE_SOURCE_DIR} -B${CMAKE_BUILD_DIR} -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="${PREFIX}"; \
+ fi; \
+ echo "Prepare: OK"
+
+check:
+ @echo "Check ..."; \
+ if [[ -f "${CMAKE_BUILD_DIR}/${PKGNAME}" ]]; then \
+ echo "Check: OK"; \
+ else \
+ echo "Check: ${CMAKE_BUILD_DIR}/${PKGNAME} not found !"; \
+ exit 1; \
+ fi
+
+build: depend prepare
+ @echo "Build ..."; \
+ $(MAKE_COMMAND) --directory=${CMAKE_BUILD_DIR}; \
+ sed -r "s/^(string version_application).*/\1;/" -i ${FILE_VER}; \
+ echo "Build: OK"
+
+uninstall:
+ @echo "Uninstall ..."
+ @for LANG in $$(find ./locale -iname "*.po" -print | sed -En "s/.+_([[:alpha:]]+)\.po/\1/p" | sort -u); do \
+# PATH_FILE_MO="${DESTDIR}${PREFIX}/share/locale/$${LANG}/LC_MESSAGES/${PKGNAME}.mo"; \
+ PATH_FILE_MO="${DESTDIR}/usr/share/locale/$${LANG}/LC_MESSAGES/${PKGNAME}.mo"; \
+ $(RM) "$${PATH_FILE_MO}"; \
+ done
+ @for SIZE in 16x16 32x32 48x48 scalable; do \
+ $(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/$${SIZE}/apps/com.ublinux.${PKGNAME}.svg"; \
+ $(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/$${SIZE}/apps/com.ublinux.${PKGNAME}.png"; \
+ done
+ @for FILE_SVG in $(wildcard *.svg); do \
+ for SIZE in 16x16 32x32 48x48 scalable; do \
+ $(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/$${SIZE}/status/$${FILE_SVG%.*}".{svg,png,jpg}; \
+ done; \
+ done
+ @for FILE_ICON in $(wildcard icons/*/*.svg); do \
+ SUB_NAME=$${FILE_ICON#*/}; SUB_NAME=$${SUB_NAME%/*}; \
+ $(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/$${SUB_NAME}/$${FILE_ICON}"; \
+ done
+ @$(RM) "${DESTDIR}${PREFIX}/bin/${PKGNAME}"
+ @$(RM) "${DESTDIR}${PREFIX}/share/applications/${PKGNAME}.desktop"
+ @if [[ "${PREFIX}" == @("/usr"|"/usr/") ]]; then \
+ $(RM) "${DESTDIR}${PREFIX}/share/polkit-1/actions/com.ublinux.${PKGNAME}.policy"; \
+ else \
+# $(RM) "${DESTDIR}${PREFIX}/share/polkit-1/actions/com.ublinux.${PKGNAME}$${PREFIX//\//-}.policy"; \
+ $(RM) "${DESTDIR}/usr/share/polkit-1/actions/com.ublinux.${PKGNAME}$${PREFIX//\//-}.policy"; \
+ fi
+ @if [[ -z "${DESTDIR}" ]]; then \
+ [[ -d "${DESTDIR}${PREFIX}/share/icons/hicolor/" ]] && gtk-update-icon-cache -fiq "${DESTDIR}${PREFIX}/share/icons/hicolor/" &>/dev/null || true; \
+ update-desktop-database --quiet &>/dev/null || true; \
+ [[ -d "${DESTDIR}${PREFIX}/share/applications" ]] && touch "${DESTDIR}${PREFIX}/share/applications" &>/dev/null || true; \
+ fi
+ @echo "Uninstall: OK"
+
+install: check uninstall
+ @echo "Install ..."
+ @for LANG in $$(find ./locale -iname "*.po" -print | sed -En "s/.+_([[:alpha:]]+)\.po/\1/p" | sort -u); do \
+ install -dm755 "${DESTDIR}${PREFIX}/share/locale/$${LANG}/LC_MESSAGES"; \
+# PATH_FILE_MO="${DESTDIR}${PREFIX}/share/locale/$${LANG}/LC_MESSAGES/${PKGNAME}.mo"; \
+ PATH_FILE_MO="${DESTDIR}/usr/share/locale/$${LANG}/LC_MESSAGES/${PKGNAME}.mo"; \
+ PKGNAME_PO="./locale/${PKGNAME}_$${LANG}.po"; [[ -f "$${PKGNAME_PO}" ]] || PKGNAME_PO= ; \
+ msgfmt --verbose --use-fuzzy --output-file "$${PATH_FILE_MO}" - < <(msgcat --use-first --no-wrap $${PKGNAME_PO} ./locale/*_$${LANG}.po); \
+ done
+ @for SIZE in 16 32 48; do \
+ install -dm755 "${DESTDIR}${PREFIX}/share/icons/hicolor/$${SIZE}x$${SIZE}/apps"; \
+ rsvg-convert -w $${SIZE} -h $${SIZE} -f svg --keep-image-data "icons/apps/com.ublinux.${PKGNAME}.svg" -o "${DESTDIR}${PREFIX}/share/icons/hicolor/$${SIZE}x$${SIZE}/apps/com.ublinux.${PKGNAME}.svg"; \
+ done
+ @for FILE_ICON in $(wildcard icons/*/*.svg); do \
+ SUB_NAME=$${FILE_ICON#*/}; SUB_NAME=$${SUB_NAME%/*}; \
+ install -Dm644 -t "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/$${SUB_NAME}" $${FILE_ICON}; \
+ done
+ @install -Dm755 -t "${DESTDIR}${PREFIX}/bin/" "${CMAKE_BUILD_DIR}/${PKGNAME}"
+ @install -Dm644 -t "${DESTDIR}${PREFIX}/share/applications/" "${PKGNAME}.desktop"
+ @if [[ "${PREFIX}" == @("/usr"|"/usr/") ]]; then \
+ install -Dm644 -t "${DESTDIR}${PREFIX}/share/polkit-1/actions/" "com.ublinux.${PKGNAME}.policy"; \
+ else \
+# install -Dm644 "com.ublinux.${PKGNAME}.policy" "${DESTDIR}${PREFIX}/share/polkit-1/actions/com.ublinux.${PKGNAME}$${PREFIX//\//-}.policy"; \
+ install -Dm644 "com.ublinux.${PKGNAME}.policy" "${DESTDIR}/usr/share/polkit-1/actions/com.ublinux.${PKGNAME}$${PREFIX//\//-}.policy"; \
+# sed -e "s+/usr/bin+${PREFIX}/bin+" -e "s+\.run+$${PREFIX//\//-}\.run+g" -i "${DESTDIR}${PREFIX}/share/polkit-1/actions/com.ublinux.${PKGNAME}$${PREFIX//\//-}.policy"; \
+ sed -e "s+/usr/bin+${PREFIX}/bin+" -e "s+\.run+$${PREFIX//\//-}\.run+g" -i "${DESTDIR}/usr/share/polkit-1/actions/com.ublinux.${PKGNAME}$${PREFIX//\//-}.policy"; \
+ fi
+ @if [[ -z "${DESTDIR}" ]]; then \
+ ldconfig -n ${DESTDIR}${PREFIX}/lib; \
+ [[ -d "${DESTDIR}${PREFIX}/share/icons/hicolor/" ]] && gtk-update-icon-cache -fiq "${DESTDIR}${PREFIX}/share/icons/hicolor/" &>/dev/null || true; \
+ update-desktop-database --quiet &>/dev/null || true; \
+ [[ -d "${DESTDIR}${PREFIX}/share/applications" ]] && touch "${DESTDIR}${PREFIX}/share/applications" &>/dev/null || true; \
+ fi
+ @echo "Install: OK"
+
+clean:
+ @echo "Clean ..."
+ @$(RM) -rd ${CMAKE_BUILD_DIR}
+ @if [[ -d "${CMAKE_BUILD_DIR}" ]]; then \
+ echo "Clean: error, compile directory exist ${CMAKE_BUILD_DIR}"; \
+ else \
+ echo "Clean: OK"; \
+ fi
+
+help:
+ @echo "The following are some of the valid targets for this Makefile:"; \
+ echo "... all (the default if no target is provided)"; \
+ echo "... init"; \
+ echo "... debug"; \
+ echo "... prepare"; \
+ echo "... compile"; \
+ echo "... install"; \
+ echo "... uninstall"; \
+ echo "... clean"
\ No newline at end of file
diff --git a/README.md b/README.md
index da6a15c..fdd0a3c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,29 @@
# ubl-settings-keyboard
+# Выполнить
+# Build
+In order to build ubl-settings-keyboard you will need:
+
+- CMake
+- C compiler
+- GTK+ 3 & dependencies
+- webkit2gtk (optional)
+
+Once you have all the necessary dependencies, you can use:
+```sh
+$ make
+```
+
+# Installation
+After a successful build, just use:
+```sh
+$ sudo make install clean
+```
+
+# Uninstallation
+After a successful build, just use:
+```sh
+$ sudo make uninstall
+```
+
+
diff --git a/com.ublinux.ubl-settings-keyboard.policy b/com.ublinux.ubl-settings-keyboard.policy
new file mode 100644
index 0000000..abe592b
--- /dev/null
+++ b/com.ublinux.ubl-settings-keyboard.policy
@@ -0,0 +1,24 @@
+
+
+
+
+ UBLinux
+ https://ublinux.ru
+
+
+ Run ubl-settings-keyboard as root
+ Запуск утилиты ubl-settings-keyboard с правами root
+ Authentication is required to run ubl-settings-keyboard
+ Требуется авторизация для запуска утилиты ubl-settings-keyboard с правами root
+
+ auth_admin
+ auth_admin
+ auth_admin
+
+ /usr/bin/ubl-settings-keyboard
+ true
+
+
+
diff --git a/gresource.xml b/gresource.xml
new file mode 100644
index 0000000..507d914
--- /dev/null
+++ b/gresource.xml
@@ -0,0 +1,14 @@
+
+
+
+ ubl-settings-keyboard.glade
+ ubl-settings-keyboard-layouts.glade
+ ubl-settings-keyboard-options.glade
+
+
+ ubl-settings-keyboard.css
+
+
+ layouts.csv
+
+
\ No newline at end of file
diff --git a/icons/apps/com.ublinux.ubl-settings-keyboard.svg b/icons/apps/com.ublinux.ubl-settings-keyboard.svg
new file mode 100644
index 0000000..eead784
--- /dev/null
+++ b/icons/apps/com.ublinux.ubl-settings-keyboard.svg
@@ -0,0 +1,6073 @@
+
+
diff --git a/layouts.csv b/layouts.csv
new file mode 100644
index 0000000..4a59bcb
--- /dev/null
+++ b/layouts.csv
@@ -0,0 +1,68 @@
+af;Afrikaans
+ar;Arabic
+as;Assamese
+az;Azerbaijani
+be;Belarusian
+bg;Bulgarian
+bn;Bengali
+bs;Bosnian
+ca;Catalan
+cs;Czech
+da;Danish
+de;German
+el;Greek
+en;English
+es;Spanish
+et;Estonian
+fi;Finnish
+fr;French
+gu;Gujarati
+he;Hebrew
+hi;Hindi
+hr;Croatian
+hu;Hungarian
+hy;Armenian
+id;Indonesian
+is;Icelandic
+it;Italian
+ja;Japanese
+ka;Georgian
+kk;Kazakh
+kn;Kannada
+ko;Korean
+ks;Kashmiri
+ku;Kurdish
+ky;Kirghiz
+lt;Lithuanian
+lv;Latvian
+mk;Macedonian
+ml;Malayalam
+mr;Marathi
+ms;Malay
+mt;Maltese
+nb;Bokmal
+nl;Dutch
+nn;Nynorsk
+or;Oriya
+pa;Punjabi
+pl;Polish
+pt;Portuguese
+ro;Romanian
+ru;Russian
+sa;Sanskrit
+sk;Slovak
+sl;Slovenian
+sq;Albanian
+sr;Serbian
+sv;Swedish
+ta;Tamil
+te;Telugu
+th;Thai
+tr;Turkish
+uk;Ukrainian
+us;American
+vi;Vietnamese
+zh;Simplified Chinese
+zh;Traditional Chinese
+zh;Chinese
+zh;Traditional Chinese
\ No newline at end of file
diff --git a/locale/ubl-settings-keyboard.pot b/locale/ubl-settings-keyboard.pot
new file mode 100644
index 0000000..933a9a2
--- /dev/null
+++ b/locale/ubl-settings-keyboard.pot
@@ -0,0 +1,480 @@
+# Language translations for ubl-settings-keyboard package.
+# Copyright (C) 2022, UBTech LLC
+# This file is distributed under the same license as the ubl-settings-keyboard package.
+# UBLinux Team , 2022
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: ubl-settings-keyboard 1.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-05-22 16:12+0600\n"
+"PO-Revision-Date: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: source/ubl-strings.h:1
+msgid "Version:"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "ubl-settings-keyboard version:"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Usage:"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "[OPTIONS]"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Options:"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Show this help"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Show package version"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Lock this help menu"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Lock configuration saving"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Lock local configration saving"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Lock global configration saving"
+msgstr ""
+
+#: source/ubl-strings.h:2
+msgid "Lock global configration loading"
+msgstr ""
+
+#: source/ubl-strings.h:4 source/ubl-strings.h:42
+msgid "Keyboard"
+msgstr ""
+
+#: source/ubl-strings.h:5
+msgid "Keyboard configuration"
+msgstr ""
+
+#: source/ubl-strings.h:7
+msgid "Operation succeeded"
+msgstr ""
+
+#: source/ubl-strings.h:8
+msgid ""
+"Warning! Application was launched without root - root-dependent actions are "
+"locked"
+msgstr ""
+
+#: source/ubl-strings.h:10
+msgid "About"
+msgstr ""
+
+#: source/ubl-strings.h:11
+msgid "Documentation"
+msgstr ""
+
+#: source/ubl-strings.h:13
+msgid "Save to local configuration"
+msgstr ""
+
+#: source/ubl-strings.h:14
+msgid "Save to global configuration"
+msgstr ""
+
+#: source/ubl-strings.h:15
+msgid "Save configuration"
+msgstr ""
+
+#: source/ubl-strings.h:16
+msgid "Save"
+msgstr ""
+
+#: source/ubl-strings.h:18
+msgid "Load local configuration"
+msgstr ""
+
+#: source/ubl-strings.h:19
+msgid "Load global configuration"
+msgstr ""
+
+#: source/ubl-strings.h:20
+msgid "Load"
+msgstr ""
+
+#: source/ubl-strings.h:22
+msgid "Cancel"
+msgstr ""
+
+#: source/ubl-strings.h:24
+msgid "Would you like to read documentation in the Web?"
+msgstr ""
+
+#: source/ubl-strings.h:25
+msgid ""
+"You will be redirected to documentation website where documentation is\n"
+"translated and supported by community."
+msgstr ""
+
+#: source/ubl-strings.h:26
+msgid "Always redirect to online documentation"
+msgstr ""
+
+#: source/ubl-strings.h:27
+msgid "Open documentation"
+msgstr ""
+
+#: source/ubl-strings.h:28
+msgid "Project Home Page"
+msgstr ""
+
+#: source/ubl-strings.h:29
+msgid "Nothing were chosen"
+msgstr ""
+
+#: source/ubl-strings.h:32
+msgid "Global configuration loading succseeded."
+msgstr ""
+
+#: source/ubl-strings.h:33
+msgid "Local configuration loading succseeded."
+msgstr ""
+
+#: source/ubl-strings.h:34
+msgid "Config loading failed"
+msgstr ""
+
+#: source/ubl-strings.h:36
+msgid "Local and global configuration saving succseeded."
+msgstr ""
+
+#: source/ubl-strings.h:37
+msgid "Global configuration saving succseeded."
+msgstr ""
+
+#: source/ubl-strings.h:38
+msgid "Local configuration saving succseeded."
+msgstr ""
+
+#: source/ubl-strings.h:40
+msgid "Console"
+msgstr ""
+
+#: source/ubl-strings.h:41
+msgid "Num Lock on boot:"
+msgstr ""
+
+#: source/ubl-strings.h:43
+msgid "Keyboard model:"
+msgstr ""
+
+#: source/ubl-strings.h:44
+msgid "Keyboard options:"
+msgstr ""
+
+#: source/ubl-strings.h:45
+msgid "Keyboard layouts:"
+msgstr ""
+
+#: source/ubl-strings.h:46
+msgid "Pick an option"
+msgstr ""
+
+#: source/ubl-strings.h:47
+msgid "Move layout up"
+msgstr ""
+
+#: source/ubl-strings.h:48
+msgid "Move layout down"
+msgstr ""
+
+#: source/ubl-strings.h:49
+msgid "Add layout"
+msgstr ""
+
+#: source/ubl-strings.h:50
+msgid "Remove layout"
+msgstr ""
+
+#: source/ubl-strings.h:51
+msgid "Default"
+msgstr ""
+
+#: source/ubl-strings.h:52
+msgid "On"
+msgstr ""
+
+#: source/ubl-strings.h:53
+msgid "Off"
+msgstr ""
+
+#: source/ubl-strings.h:54
+msgid "Accept"
+msgstr ""
+
+
+msgid "Afrikaans"
+msgstr ""
+
+msgid "Arabic"
+msgstr ""
+
+msgid "Assamese"
+msgstr ""
+
+msgid "Azerbaijani"
+msgstr ""
+
+msgid "Belarusian"
+msgstr ""
+
+msgid "Bulgarian"
+msgstr ""
+
+msgid "Bengali"
+msgstr ""
+
+msgid "Bosnian"
+msgstr ""
+
+msgid "Catalan"
+msgstr ""
+
+msgid "Czech"
+msgstr ""
+
+msgid "Danish"
+msgstr ""
+
+msgid "German"
+msgstr ""
+
+msgid "Greek"
+msgstr ""
+
+msgid "English"
+msgstr ""
+
+msgid "Spanish"
+msgstr ""
+
+msgid "Estonian"
+msgstr ""
+
+msgid "Finnish"
+msgstr ""
+
+msgid "French"
+msgstr ""
+
+msgid "Gujarati"
+msgstr ""
+
+msgid "Hebrew"
+msgstr ""
+
+msgid "Hindi"
+msgstr ""
+
+msgid "Croatian"
+msgstr ""
+
+msgid "Hungarian"
+msgstr ""
+
+msgid "Armenian"
+msgstr ""
+
+msgid "Indonesian"
+msgstr ""
+
+msgid "Icelandic"
+msgstr ""
+
+msgid "Italian"
+msgstr ""
+
+msgid "Japanese"
+msgstr ""
+
+msgid "Georgian"
+msgstr ""
+
+msgid "Kazakh"
+msgstr ""
+
+msgid "Kannada"
+msgstr ""
+
+msgid "Korean"
+msgstr ""
+
+msgid "Kashmiri"
+msgstr ""
+
+msgid "Kurdish"
+msgstr ""
+
+msgid "Kirghiz"
+msgstr ""
+
+msgid "Lithuanian"
+msgstr ""
+
+msgid "Latvian"
+msgstr ""
+
+msgid "Macedonian"
+msgstr ""
+
+msgid "Malayalam"
+msgstr ""
+
+msgid "Marathi"
+msgstr ""
+
+msgid "Malay"
+msgstr ""
+
+msgid "Maltese"
+msgstr ""
+
+msgid "Bokmal"
+msgstr ""
+
+msgid "Dutch"
+msgstr ""
+
+msgid "Nynorsk"
+msgstr ""
+
+msgid "Oriya"
+msgstr ""
+
+msgid "Punjabi"
+msgstr ""
+
+msgid "Polish"
+msgstr ""
+
+msgid "Portuguese"
+msgstr ""
+
+msgid "Romanian"
+msgstr ""
+
+msgid "Russian"
+msgstr ""
+
+msgid "Sanskrit"
+msgstr ""
+
+msgid "Slovak"
+msgstr ""
+
+msgid "Slovenian"
+msgstr ""
+
+msgid "Albanian"
+msgstr ""
+
+msgid "Serbian"
+msgstr ""
+
+msgid "Swedish"
+msgstr ""
+
+msgid "Tamil"
+msgstr ""
+
+msgid "Telugu"
+msgstr ""
+
+msgid "Thai"
+msgstr ""
+
+msgid "Turkish"
+msgstr ""
+
+msgid "Ukrainian"
+msgstr ""
+
+msgid "American"
+msgstr ""
+
+msgid "Vietnamese"
+msgstr ""
+
+msgid "Simplified Chinese"
+msgstr ""
+
+msgid "Traditional Chinese"
+msgstr ""
+
+msgid "Chinese"
+msgstr ""
+
+msgid "Generic 86-key PC"
+msgstr ""
+
+msgid "Generic 101-key PC"
+msgstr ""
+
+msgid "Generic 102-key PC"
+msgstr ""
+
+msgid "Generic 104-key PC"
+msgstr ""
+
+msgid "Generic 104-key PC with L-shaped Enter key"
+msgstr ""
+
+msgid "Generic 105-key PC"
+msgstr ""
+
+msgid "Dell 101-key PC"
+msgstr ""
+
+msgid "Dell Latitude laptop"
+msgstr ""
+
+msgid "Dell Precision M65 laptop"
+msgstr ""
+
+msgid "Dell Inspiron 6000/8000 laptop"
+msgstr ""
+
+msgid "Dell Precision M laptop"
+msgstr ""
+
+msgid "Fujitsu-Siemens Amilo laptop"
+msgstr ""
+
+msgid "Hewlett-Packard Mini 110 laptop"
+msgstr ""
+
+msgid "Asus laptop"
+msgstr ""
+
+msgid "Apple laptop"
+msgstr ""
+
+msgid "eMachines m6800 laptop"
+msgstr ""
\ No newline at end of file
diff --git a/locale/ubl-settings-keyboard_ru.po b/locale/ubl-settings-keyboard_ru.po
new file mode 100644
index 0000000..9257e06
--- /dev/null
+++ b/locale/ubl-settings-keyboard_ru.po
@@ -0,0 +1,486 @@
+# Russian translations for ubl-settings-keyboard package.
+# Copyright (C) 2022, UBTech LLC
+# This file is distributed under the same license as the ubl-settings-keyboard package.
+# UBLinux Team , 2022
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: ubl-settings-keyboard 1.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-05-22 16:12+0600\n"
+"PO-Revision-Date: 2023-01-01 00:00+0600\n"
+"Last-Translator: UBLinux Team \n"
+"Language-Team: Russian - UBLinux Team \n"
+"Language: Russian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: source/ubl-strings.h:1
+msgid "Version:"
+msgstr "Версия:"
+
+#: source/ubl-strings.h:2
+msgid "ubl-settings-keyboard version:"
+msgstr "Версия ubl-settings-keyboard: "
+
+#: source/ubl-strings.h:2
+msgid "Usage:"
+msgstr "Использование:"
+
+#: source/ubl-strings.h:2
+msgid "[OPTIONS]"
+msgstr "[АРГУМЕНТЫ]"
+
+#: source/ubl-strings.h:2
+msgid "Options:"
+msgstr "Аргументы:"
+
+#: source/ubl-strings.h:2
+msgid "Show this help"
+msgstr "Показать параметры справки"
+
+#: source/ubl-strings.h:2
+msgid "Show package version"
+msgstr "Показать текущую версию"
+
+#: source/ubl-strings.h:2
+msgid "Lock this help menu"
+msgstr "Блокировка вызова справки"
+
+#: source/ubl-strings.h:2
+msgid "Lock configuration saving"
+msgstr "Блокировка сохранения локальной и глобальной конфигурации"
+
+#: source/ubl-strings.h:2
+msgid "Lock local configration saving"
+msgstr "Блокировка сохранения локальной конфигурации"
+
+#: source/ubl-strings.h:2
+msgid "Lock global configration saving"
+msgstr "Блокировка сохранения глобальной конфигурации"
+
+#: source/ubl-strings.h:2
+msgid "Lock global configration loading"
+msgstr "Блокировка загрузки глобальной конфигурации"
+
+#: source/ubl-strings.h:4 source/ubl-strings.h:42
+msgid "Keyboard"
+msgstr "Клавиатура"
+
+#: source/ubl-strings.h:5
+msgid "Keyboard configuration"
+msgstr "Настройки Клавиатуры"
+
+#: source/ubl-strings.h:7
+msgid "Operation succeeded"
+msgstr "Операция завершена"
+
+#: source/ubl-strings.h:8
+msgid ""
+"Warning! Application was launched without root - root-dependent actions are "
+"locked"
+msgstr ""
+"Внимание! Приложение было запущено без прав суперпользователя - действия, "
+"требующие их наличия заблокированы"
+
+#: source/ubl-strings.h:10
+msgid "About"
+msgstr "О программе"
+
+#: source/ubl-strings.h:11
+msgid "Documentation"
+msgstr "Справка"
+
+#: source/ubl-strings.h:13
+msgid "Save to local configuration"
+msgstr "Сохранить в локальную конфигурацию"
+
+#: source/ubl-strings.h:14
+msgid "Save to global configuration"
+msgstr "Сохранить в глобальную конфигурацию"
+
+#: source/ubl-strings.h:15
+msgid "Save configuration"
+msgstr "Сохранить конфигурацию"
+
+#: source/ubl-strings.h:16
+msgid "Save"
+msgstr "Сохранить"
+
+#: source/ubl-strings.h:18
+msgid "Load local configuration"
+msgstr "Загрузить локальную конфигуруцию"
+
+#: source/ubl-strings.h:19
+msgid "Load global configuration"
+msgstr "Загрузить глобальную конфигурацию"
+
+#: source/ubl-strings.h:20
+msgid "Load"
+msgstr "Загрузить"
+
+#: source/ubl-strings.h:22
+msgid "Cancel"
+msgstr "Отмена"
+
+#: source/ubl-strings.h:24
+msgid "Would you like to read documentation in the Web?"
+msgstr "Вы хотите прочитать справку в Сети?"
+
+#: source/ubl-strings.h:25
+msgid ""
+"You will be redirected to documentation website where documentation is\n"
+"translated and supported by community."
+msgstr ""
+"Вы будете перенаправлены на сайт с документацией, где страницы помощи\n"
+"переводятся и поддерживаются сообществом."
+
+#: source/ubl-strings.h:26
+msgid "Always redirect to online documentation"
+msgstr "Всегда перенаправлять"
+
+#: source/ubl-strings.h:27
+msgid "Open documentation"
+msgstr "Прочитать справку"
+
+#: source/ubl-strings.h:28
+msgid "Project Home Page"
+msgstr "Домашняя страница проекта"
+
+#: source/ubl-strings.h:29
+msgid "Nothing were chosen"
+msgstr "Ничего не было выбрано"
+
+#: source/ubl-strings.h:32
+msgid "Global configuration loading succseeded."
+msgstr "Успешно загружена глобальная конфигурация"
+
+#: source/ubl-strings.h:33
+msgid "Local configuration loading succseeded."
+msgstr "Успешно загружена локальная конфигурация"
+
+#: source/ubl-strings.h:34
+msgid "Config loading failed"
+msgstr "Ошибка загрузки конфигурации"
+
+#: source/ubl-strings.h:36
+msgid "Local and global configuration saving succseeded."
+msgstr "Успешно записаны локальная и глобальная конфигурация"
+
+#: source/ubl-strings.h:37
+msgid "Global configuration saving succseeded."
+msgstr "Успешно записана глобальная конфигурация"
+
+#: source/ubl-strings.h:38
+msgid "Local configuration saving succseeded."
+msgstr "Успешно записана локальная конфигурация"
+
+#: source/ubl-strings.h:40
+msgid "Console"
+msgstr "Консоль"
+
+#: source/ubl-strings.h:41
+msgid "Num Lock on boot:"
+msgstr "Num Lock при загрузке:"
+
+#: source/ubl-strings.h:43
+msgid "Keyboard model:"
+msgstr "Модель клавиатуры:"
+
+#: source/ubl-strings.h:44
+msgid "Keyboard options:"
+msgstr "Опции клавиатуры:"
+
+#: source/ubl-strings.h:45
+msgid "Keyboard layouts:"
+msgstr "Раскладки клавиатуры:"
+
+#: source/ubl-strings.h:46
+msgid "Pick an option"
+msgstr "Выбрать опцию"
+
+#: source/ubl-strings.h:47
+msgid "Move layout up"
+msgstr "Переместить раскладку выше"
+
+#: source/ubl-strings.h:48
+msgid "Move layout down"
+msgstr "Переместить раскладку ниже"
+
+#: source/ubl-strings.h:49
+msgid "Add layout"
+msgstr "Добавить раскладку"
+
+#: source/ubl-strings.h:50
+msgid "Remove layout"
+msgstr "Удалить раскладку"
+
+#: source/ubl-strings.h:51
+msgid "Default"
+msgstr "По умолчанию"
+
+#: source/ubl-strings.h:52
+msgid "On"
+msgstr "Включить"
+
+#: source/ubl-strings.h:53
+msgid "Off"
+msgstr "Выключить"
+
+#: source/ubl-strings.h:54
+msgid "Accept"
+msgstr "Принять"
+
+msgid "Afrikaans"
+msgstr "Африканский"
+
+msgid "Arabic"
+msgstr "Арабский"
+
+msgid "Assamese"
+msgstr "Ассамский"
+
+msgid "Azerbaijani"
+msgstr "Азербайджанский"
+
+msgid "Belarusian"
+msgstr "Беларусский"
+
+msgid "Bulgarian"
+msgstr "Болгарский"
+
+msgid "Bengali"
+msgstr "Бенгальский"
+
+msgid "Bosnian"
+msgstr "Боснийский"
+
+msgid "Catalan"
+msgstr "Каталонский"
+
+msgid "Czech"
+msgstr "Чешский"
+
+msgid "Danish"
+msgstr "Датский"
+
+msgid "German"
+msgstr "Немецкий"
+
+msgid "Greek"
+msgstr "Греческий"
+
+msgid "English"
+msgstr "Английский"
+
+msgid "Spanish"
+msgstr "Испанский"
+
+msgid "Estonian"
+msgstr "Эстонский"
+
+msgid "Finnish"
+msgstr "Финский"
+
+msgid "French"
+msgstr "Французский"
+
+msgid "Gujarati"
+msgstr "Гуджаратский"
+
+msgid "Hebrew"
+msgstr "Иврит"
+
+msgid "Hindi"
+msgstr "Хинди"
+
+msgid "Croatian"
+msgstr "Хорватский"
+
+msgid "Hungarian"
+msgstr "Венгерский"
+
+msgid "Armenian"
+msgstr "Армянский"
+
+msgid "Indonesian"
+msgstr "Индонезийский"
+
+msgid "Icelandic"
+msgstr "Исландский"
+
+msgid "Italian"
+msgstr "Итальянский"
+
+msgid "Japanese"
+msgstr "Японский"
+
+msgid "Georgian"
+msgstr "Грузинский"
+
+msgid "Kazakh"
+msgstr "Казахский"
+
+msgid "Kannada"
+msgstr "Каннада"
+
+msgid "Korean"
+msgstr "Корейский"
+
+msgid "Kashmiri"
+msgstr "Кашмирский"
+
+msgid "Kurdish"
+msgstr "Курдский"
+
+msgid "Kirghiz"
+msgstr "Киргизский"
+
+msgid "Lithuanian"
+msgstr "Литовский"
+
+msgid "Latvian"
+msgstr "Латышский"
+
+msgid "Macedonian"
+msgstr "Македонский"
+
+msgid "Malayalam"
+msgstr "Малаялам"
+
+msgid "Marathi"
+msgstr "Маратхи"
+
+msgid "Malay"
+msgstr "Малайский"
+
+msgid "Maltese"
+msgstr "Мальтийский"
+
+msgid "Bokmal"
+msgstr "Букмол"
+
+msgid "Dutch"
+msgstr "Нидерландский"
+
+msgid "Nynorsk"
+msgstr "Норвежский"
+
+msgid "Oriya"
+msgstr "Ория"
+
+msgid "Punjabi"
+msgstr "Панджаби"
+
+msgid "Polish"
+msgstr "Польский"
+
+msgid "Portuguese"
+msgstr "Португальский"
+
+msgid "Romanian"
+msgstr "Румынский"
+
+msgid "Russian"
+msgstr "Русский"
+
+msgid "Sanskrit"
+msgstr "Санскрит"
+
+msgid "Slovak"
+msgstr "Словацкий"
+
+msgid "Slovenian"
+msgstr "Словенский"
+
+msgid "Albanian"
+msgstr "Албанский"
+
+msgid "Serbian"
+msgstr "Сербский"
+
+msgid "Swedish"
+msgstr "Шведский"
+
+msgid "Tamil"
+msgstr "Тамильский"
+
+msgid "Telugu"
+msgstr "Тулугу"
+
+msgid "Thai"
+msgstr "Тайский"
+
+msgid "Turkish"
+msgstr "Турецкий"
+
+msgid "Ukrainian"
+msgstr "Украинский"
+
+msgid "American"
+msgstr "Американский английский"
+
+msgid "Vietnamese"
+msgstr "Вьетнамский"
+
+msgid "Simplified Chinese"
+msgstr "Упрощённый Китайский"
+
+msgid "Traditional Chinese"
+msgstr "Традиционный Китайский"
+
+msgid "Chinese"
+msgstr "Китайский"
+
+msgid "Generic 86-key PC"
+msgstr "Обычная 86-клавишная"
+
+msgid "Generic 101-key PC"
+msgstr "Обычная 101-клавишная"
+
+msgid "Generic 102-key PC"
+msgstr "Обычная 102-клавишная"
+
+msgid "Generic 104-key PC"
+msgstr "Обычная 104-клавишная"
+
+msgid "Generic 104-key PC with L-shaped Enter key"
+msgstr "Обычная 104-клавишная (Enter в форме буквы L)"
+
+msgid "Generic 105-key PC"
+msgstr "Обычная 105-клавишная"
+
+msgid "Dell 101-key PC"
+msgstr "Dell 101-клавишная"
+
+msgid "Dell Latitude laptop"
+msgstr "Ноутбук Dell Latitude"
+
+msgid "Dell Precision M65 laptop"
+msgstr "Ноутбук Dell Precision M65"
+
+msgid "Dell Inspiron 6000/8000 laptop"
+msgstr "Ноутбук Dell Inspiron 6000/8000"
+
+msgid "Dell Precision M laptop"
+msgstr "Ноутбук Dell Precision M"
+
+msgid "Fujitsu-Siemens Amilo laptop"
+msgstr "Ноутбук Fujitsu-Siemens Amilo"
+
+msgid "Hewlett-Packard Mini 110 laptop"
+msgstr "Ноутбук Hewlett-Packard Mini 110"
+
+msgid "Asus laptop"
+msgstr "Ноутбук Asus"
+
+msgid "Apple laptop"
+msgstr "Ноутбук Apple"
+
+msgid "eMachines m6800 laptop"
+msgstr "Ноутбук eMachines m6800"
+
+#~ msgid "Acer laptop"
+#~ msgstr "Ноутбук Acer"
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
new file mode 100644
index 0000000..5cabe32
--- /dev/null
+++ b/source/CMakeLists.txt
@@ -0,0 +1,100 @@
+cmake_minimum_required(VERSION 3.7)
+project(ubl-settings-keyboard)
+
+find_package(PkgConfig REQUIRED)
+
+pkg_check_modules(GTK REQUIRED gtk+-3.0)
+include_directories(${GTK_INCLUDE_DIRS})
+link_directories(${GTK_LIBRARY_DIRS})
+add_definitions(${GTK_CFLAGS_OTHER})
+
+pkg_check_modules(VTE291 REQUIRED vte-2.91)
+include_directories(${VTE291_INCLUDE_DIRS})
+link_directories(${VTE291_LIBRARY_DIRS})
+add_definitions(${VTE291_CFLAGS_OTHER})
+
+find_library(WEBKIT_LIBRARIES_FOUND webkit2gtk-4.0 webkit2gtk-web-extension-4.0)
+
+option(WEBKIT_FOUND "No" OFF)
+if(WEBKIT_LIBRARIES_FOUND)
+ option(WEBKIT_FOUND "Yes" ON)
+ PKG_CHECK_MODULES(WEBKIT REQUIRED webkit2gtk-4.0 webkit2gtk-web-extension-4.0)
+ include_directories(${WEBKIT_INCLUDE_DIRS})
+ link_directories(${WEBKIT_LIBRARY_DIRS})
+ add_definitions(${WEBKIT_CFLAGS_OTHER})
+endif()
+
+set(GRESOURCE_C resources.c)
+set(GRESOURCE_XML gresource.xml)
+
+find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED)
+add_custom_target(GLADE ubl-settings-keyboard.glade)
+
+set(DEPENDFILES
+ ../ubl-settings-keyboard.glade
+ ../ubl-settings-keyboard-layouts.glade
+ ../ubl-settings-keyboard-options.glade
+ ../layouts.csv
+ ../gresource.xml
+ ../ubl-settings-keyboard.css
+ )
+
+file(COPY ${DEPENDFILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+
+add_custom_command(
+ OUTPUT ${GRESOURCE_C}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${GLIB_COMPILE_RESOURCES}
+ ARGS
+ --generate-source
+ --target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}
+ ${GRESOURCE_XML}
+ VERBATIM
+ MAIN_DEPENDENCY ${GRESOURCE_XML}
+ DEPENDS
+ ${GLADE}
+)
+add_custom_target(
+ dummy-resource
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}
+)
+
+add_definitions(-DVTE_INCLUDE)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -Wmissing-declarations -fdiagnostics-color=always \
+ -O2 -pipe -fno-plt -fexceptions \
+ -Wformat -Werror=format-security \
+ -fstack-clash-protection -fcf-protection")
+
+string(FIND "${CMAKE_CXX_FLAGS}" "-D_FORTIFY_SOURCE" FORTIFY_FOUND)
+
+if(FORTIFY_FOUND EQUAL -1)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wp,-D_FORTIFY_SOURCE=2")
+endif()
+
+set(SOURCE_FILES
+ ubl-settings-keyboard.c
+ ubl-settings-keyboard.h
+ ubl-strings.h
+ )
+
+set(LIBRARIES
+ ${GTK_LIBRARIES}
+ ${WEBKIT_LIBRARIES}
+ ${UTILS_LIBRARIES}
+ ${VTE291_LIBRARIES}
+ pthread
+ ublsettings
+ ublsettings-gtk3
+ ublsettingsui-gtk3)
+
+
+add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C})
+target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBRARIES})
+target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR})
+set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}
+ PROPERTIES GENERATED TRUE
+)
+install(TARGETS ${PROJECT_NAME} DESTINATION bin)
+add_dependencies(${PROJECT_NAME} dummy-resource)
\ No newline at end of file
diff --git a/source/ubl-settings-keyboard.c b/source/ubl-settings-keyboard.c
new file mode 100644
index 0000000..c30193a
--- /dev/null
+++ b/source/ubl-settings-keyboard.c
@@ -0,0 +1,433 @@
+#include "ubl-settings-keyboard.h"
+
+config main_config;
+
+void on_save_done(main_window *, config_str output, int size){
+ char *final_output = yon_char_parsed_to_string(output,size,"");
+ if (final_output){
+ printf("%s\n",final_output);
+ free(final_output);
+ }
+ yon_char_parsed_free(output,size);
+ textdomain(template_ui_LocaleName);
+ switch (main_config.save_config){
+ case 0:
+ yon_ubl_status_box_render(GLOBAL_SAVE_SUCCESS_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE);
+ break;
+ case 1:
+ yon_ubl_status_box_render(LOCAL_SAVE_SUCCESS_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE);
+ break;
+ case 2:
+ yon_ubl_status_box_render(GLOBAL_LOCAL_SAVE_SUCCESS_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE);
+ break;
+ }
+ textdomain(LocaleName);
+
+}
+
+void on_config_global_local_save(GtkWidget *, main_window *){
+ main_config.save_config=3;
+ yon_save_proceed(NULL,YON_CONFIG_BOTH,config_get_global_command,NULL);
+}
+
+void on_config_local_save(GtkWidget *, main_window *){
+ main_config.save_config=1;
+ yon_save_proceed("system",YON_CONFIG_LOCAL,config_get_local_command,NULL);
+
+}
+
+void on_config_global_save(GtkWidget *, main_window *){
+ main_config.save_config=0;
+ yon_save_proceed("global",YON_CONFIG_GLOBAL,config_get_global_command,NULL);
+
+}
+
+void on_config_custom_save(GtkWidget *, main_window *){
+ main_config.save_config=1;
+ template_saving_window *window = yon_save_proceed(NULL,YON_CONFIG_CUSTOM,yon_config_get_custom_command("system"),NULL);
+ if (window){};
+}
+
+void on_config_local_load(GtkWidget *,main_window *widgets){
+ yon_load_proceed(YON_CONFIG_LOCAL);
+ g_idle_add((GSourceFunc)yon_interface_update,widgets);
+ main_config.load_mode=1;
+}
+
+void on_config_global_load(GtkWidget *,main_window *widgets){
+ yon_load_proceed(YON_CONFIG_GLOBAL);
+ g_idle_add((GSourceFunc)yon_interface_update,widgets);
+ main_config.load_mode=0;
+
+}
+
+void on_config_custom_load(GtkWidget *,main_window *widgets){
+ yon_load_proceed(YON_CONFIG_CUSTOM);
+ textdomain(template_ui_LocaleName);
+ yon_ubl_status_box_render(GLOBAL_LOAD_SUCCESS_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE);
+ textdomain(LocaleName);
+ main_config.load_mode=3;
+ g_idle_add((GSourceFunc)yon_interface_update,widgets);
+}
+
+void yon_load_proceed(YON_CONFIG_TYPE type){
+ yon_config_clean();
+ if (!yon_char_is_empty(config_get_default_command))
+ yon_config_load_config(YON_CONFIG_DEFAULT,config_get_default_command,NULL);
+ if (type==YON_CONFIG_GLOBAL){
+ yon_config_load_config(type,config_get_global_command,NULL);
+ } else if (type==YON_CONFIG_LOCAL){
+ yon_config_load_config(type,config_get_local_command,NULL);
+ } else if (type==YON_CONFIG_CUSTOM){
+ char *path="";
+ textdomain(template_ui_LocaleName);
+ GtkWidget *dialog = gtk_file_chooser_dialog_new(template_app_information.app_title,NULL,GTK_FILE_CHOOSER_ACTION_SAVE,CANCEL_LABEL,GTK_RESPONSE_CANCEL,OPEN_LABEL,GTK_RESPONSE_ACCEPT,NULL);
+ textdomain(LocaleName);
+ gtk_window_set_icon_name(GTK_WINDOW(dialog),"com.ublinux.ubl-settings-services");
+ gtk_window_set_title(GTK_WINDOW(dialog),TITLE_LABEL);
+ GtkFileFilter *filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(filter,"*.ini");
+ gtk_file_filter_set_name(filter, "*.ini");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),filter);
+ gtk_widget_show(dialog);
+ int response = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (response == GTK_RESPONSE_ACCEPT){
+ char *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ if (!yon_char_is_empty(file)){
+ path=file;
+ }
+ gtk_widget_destroy(dialog);
+ } else {
+ gtk_widget_destroy(dialog);
+ }
+ char *command = yon_config_get_custom_command(path);
+ yon_config_load_config(type,command,NULL);
+ }
+}
+
+gboolean yon_interface_update(main_window *widgets){
+ gtk_list_store_clear(widgets->layoutsList);
+
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->ModelCombo),0);
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->NumLockCombo),0);
+ GtkTreeIter iter;
+ gtk_entry_set_text(GTK_ENTRY(widgets->OptionsEntry),DEFAULT_LABEL);
+ char *name = yon_config_get_by_key("XkbModel");
+ char *id;
+ if (name) {
+ int valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(widgets->modelsList),&iter);
+ for (;valid;valid=gtk_tree_model_iter_next(GTK_TREE_MODEL(widgets->modelsList),&iter)){
+ gtk_tree_model_get(GTK_TREE_MODEL(widgets->modelsList),&iter,0,&id,-1);
+ if (!strcmp(name,id)){
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(widgets->ModelCombo),&iter);
+ break;
+ }
+ }
+ } else gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->ModelCombo),0);
+ free(name);
+ name = yon_config_get_by_key("XkbOptions");
+ if (name) {
+ char *id, *rname;
+ gtk_entry_set_text(GTK_ENTRY(widgets->OptionsEntry),name);
+ int valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(main_config.options_list),&iter);
+ for (;valid;valid=gtk_tree_model_iter_next(GTK_TREE_MODEL(main_config.options_list),&iter)){
+ gtk_tree_model_get(GTK_TREE_MODEL(main_config.options_list),&iter,0,&id,1,&rname,-1);
+ if (!strcmp(id,name)) gtk_entry_set_text(GTK_ENTRY(widgets->OptionsEntry),rname);
+ }
+ }
+ free(name);
+ name = yon_config_get_by_key("NUMLOCK");
+ if (name) {
+ if (!strcmp(name,"yes")) gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->NumLockCombo),1);
+ else if (!strcmp(name,"no")) gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->NumLockCombo),2);
+ }
+ else gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->NumLockCombo),0);
+ free(name);
+ if (main_config.layouts_list){
+ int size=0;
+ name = yon_config_get_by_key("XkbLayout");
+ config_str layouts = yon_char_parse(name,&size,",");
+ GtkTreeIter iter;
+ char *rid,*rname;
+ gtk_list_store_clear(widgets->layoutsList);
+ for (int i=0;ilayoutsList,&iter);
+ gtk_list_store_set(widgets->layoutsList,&iter,0,rname,1,rid,2,0,-1);
+ }
+ }
+ }
+ }
+ return G_SOURCE_REMOVE;
+}
+
+void on_num_lock_changed(GtkComboBox *self, main_window *){
+ switch (gtk_combo_box_get_active(self)){
+ case 0:
+ yon_config_remove_by_key(num_lock_boot_parameter);
+ break;
+ case 1: yon_config_register(num_lock_boot_parameter,num_lock_boot_parameter_command,"yes");
+ break;
+ case 2:yon_config_register(num_lock_boot_parameter,num_lock_boot_parameter_command,"no");
+ break;
+ }
+}
+
+void on_model_changed(GtkComboBoxText *self, main_window *widgets){
+ switch (gtk_combo_box_get_active(GTK_COMBO_BOX(self))){
+ case 0:
+ yon_config_remove_by_key(model_parameter);
+ break;
+ default:
+ char *id;
+ GtkTreeIter iter;
+ gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widgets->ModelCombo),&iter);
+ gtk_tree_model_get(GTK_TREE_MODEL(widgets->modelsList),&iter,1,&id,-1);
+ yon_config_register(model_parameter,model_parameter_command,id);
+ break;
+ }
+
+}
+
+void on_options_accept(GtkWidget *self, dictionary *dict){
+ main_window *widgets = yon_dictionary_get_data(dict->first,main_window*);
+ layouts_window *window = yon_dictionary_get_data(dict->first->next,layouts_window*);
+ GtkTreeModel *model = GTK_TREE_MODEL(window->list);
+ GtkTreeIter iter;
+ char *name, *id;
+ if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(window->MainTree)),&model,&iter)){
+ gtk_tree_model_get(model,&iter,0,&id,1,&name,-1);
+ gtk_entry_set_text(GTK_ENTRY(widgets->OptionsEntry),name);
+ yon_config_register(options_parameter,options_parameter_command,id);
+
+ }
+ on_subwindow_close(self);
+}
+
+void yon_layouts_save(main_window *widgets){
+ GtkTreeIter iter;
+ GtkTreeIter child_iter;
+ int size;
+ config_str parsed = NULL;
+ for_iter(widgets->layoutsFilter,&iter){
+ char *name, *id;
+ gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(widgets->layoutsFilter),&child_iter,&iter);
+ gtk_tree_model_get(GTK_TREE_MODEL(widgets->layoutsList),&child_iter,0,&name,1,&id,-1);
+ yon_char_parsed_add_or_create_if_exists(parsed,&size,id);
+ }
+ if (parsed&&size>0){
+ yon_config_register(keyboard_layout_parameter,keyboard_layout_parameter_command,yon_char_parsed_to_string(parsed,size,","));
+ yon_char_parsed_free(parsed,size);
+ } else {
+ yon_config_remove_by_key(keyboard_layout_parameter);
+ }
+}
+
+void on_options_open(GtkWidget *, main_window *widgets){
+ GtkBuilder *builder = gtk_builder_new_from_resource(glade_layouts_path);
+ layouts_window *window = malloc(sizeof(layouts_window));
+ window->Window = yon_gtk_builder_get_widget(builder,"Window");
+ window->AcceptButton = yon_gtk_builder_get_widget(builder,"AcceptButton");
+ window->CancelButton = yon_gtk_builder_get_widget(builder,"CancelButton");
+ window->MainTree = yon_gtk_builder_get_widget(builder,"LayoutsTree");
+ window->list = main_config.options_list;
+ gtk_tree_view_set_model(GTK_TREE_VIEW(window->MainTree),GTK_TREE_MODEL(window->list));
+ dictionary *dict = NULL;
+ yon_dictionary_add_or_create_if_exists_with_data(dict,"widgets",widgets);
+ yon_dictionary_add_or_create_if_exists_with_data(dict,"window",window);
+ g_signal_connect(G_OBJECT(window->CancelButton),"clicked",G_CALLBACK(on_subwindow_close),NULL);
+ g_signal_connect(G_OBJECT(window->AcceptButton),"clicked",G_CALLBACK(on_options_accept),dict);
+}
+
+void on_layouts_accept(GtkWidget *self, dictionary *dict){
+ main_window *widgets = yon_dictionary_get_data(dict->first,main_window*);
+ layouts_window *window = yon_dictionary_get_data(dict->first->next,layouts_window*);
+ GtkTreeModel *model = GTK_TREE_MODEL(window->list);
+ GList *list = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(window->MainTree)),&model);
+ char *name;
+ char *id;
+ GtkTreeIter iter, lwiter;
+ GtkTreePath *pth;
+ for (guint i=0;ilayoutsList,&iter);
+ gtk_tree_model_get(model,&lwiter,0,&name,1,&id,-1);
+ gtk_list_store_set(widgets->layoutsList,&iter,1,name,0,id,2,1,-1);
+ }
+ yon_layouts_save(widgets);
+ on_subwindow_close(self);
+}
+
+void on_layouts_add(GtkWidget *, main_window *widgets){
+ GtkBuilder *builder = gtk_builder_new_from_resource(glade_layouts_path);
+ layouts_window *window = malloc(sizeof(layouts_window));
+ window->Window = yon_gtk_builder_get_widget(builder,"Window");
+ window->AcceptButton = yon_gtk_builder_get_widget(builder,"AcceptButton");
+ window->CancelButton = yon_gtk_builder_get_widget(builder,"CancelButton");
+ window->MainTree = yon_gtk_builder_get_widget(builder,"LayoutsTree");
+ window->list = main_config.layouts_list;
+ gtk_tree_view_set_model(GTK_TREE_VIEW(window->MainTree), GTK_TREE_MODEL(window->list));
+ gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(window->MainTree)),GTK_SELECTION_MULTIPLE);
+
+ dictionary *dict = NULL;
+ yon_dictionary_add_or_create_if_exists_with_data(dict,"widgets",widgets);
+ yon_dictionary_add_or_create_if_exists_with_data(dict,"window",window);
+
+ g_signal_connect(G_OBJECT(window->CancelButton),"clicked",G_CALLBACK(on_subwindow_close),NULL);
+ g_signal_connect(G_OBJECT(window->AcceptButton),"clicked",G_CALLBACK(on_layouts_accept),dict);
+}
+
+void on_layouts_remove(GtkWidget *, main_window *widgets){
+ GtkTreeModel *model = GTK_TREE_MODEL(widgets->layoutsList);
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->LayoutsTree)),&model,&iter)){
+ GtkTreeIter iter_converted;
+ gtk_tree_model_filter_convert_iter_to_child_iter(widgets->layoutsFilter,&iter_converted,&iter);
+ gtk_list_store_remove(widgets->layoutsList,&iter_converted);
+ }
+}
+
+void on_move_up(GtkWidget *, main_window *widgets){
+ GtkTreeModel *model = GTK_TREE_MODEL(widgets->layoutsFilter);
+ GtkTreeIter iter,*previter;
+ if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->LayoutsTree)),&model,&iter)){
+ previter = gtk_tree_iter_copy(&iter);
+ if (gtk_tree_model_iter_previous(model,previter))
+ {
+ GtkTreeIter iter_converted, previter_converted;
+ gtk_tree_model_filter_convert_iter_to_child_iter(widgets->layoutsFilter,&iter_converted,&iter);
+ gtk_tree_model_filter_convert_iter_to_child_iter(widgets->layoutsFilter,&previter_converted,previter);
+ gtk_list_store_move_before(widgets->layoutsList,&iter_converted,&previter_converted);
+ yon_layouts_save(widgets);
+ }
+ }
+}
+
+void on_move_down(GtkWidget *, main_window *widgets){
+ GtkTreeModel *model = GTK_TREE_MODEL(widgets->layoutsFilter);
+ GtkTreeIter iter,*nextiter;
+ if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->LayoutsTree)),&model,&iter)){
+ nextiter = gtk_tree_iter_copy(&iter);
+ if (gtk_tree_model_iter_next(model,nextiter)){
+ GtkTreeIter iter_converted, nextiter_converted;
+ gtk_tree_model_filter_convert_iter_to_child_iter(widgets->layoutsFilter,&iter_converted,&iter);
+ gtk_tree_model_filter_convert_iter_to_child_iter(widgets->layoutsFilter,&nextiter_converted,nextiter);
+ gtk_list_store_move_after(widgets->layoutsList,&iter_converted,&nextiter_converted);
+ yon_layouts_save(widgets);
+ }
+ }
+
+}
+
+
+
+// standard functions
+
+
+void yon_main_window_complete(main_window *widgets){
+ widgets = yon_remalloc(widgets,sizeof(main_window));
+ GtkBuilder *builder = gtk_builder_new_from_resource(glade_path);
+ gtk_box_pack_start(GTK_BOX(widgets->InterfaceBox),yon_gtk_builder_get_widget(builder,"BoxMain"),1,1,0);
+ // Custom widgets configuration
+ {
+
+ widgets->NumLockCombo = yon_gtk_builder_get_widget(builder,"NumlockCombo");
+ widgets->ModelCombo = yon_gtk_builder_get_widget(builder,"ModelCombo");
+ widgets->keyboard = yon_gtk_builder_get_widget(builder,"keyboard");
+ widgets->keytable = yon_gtk_builder_get_widget(builder,"keytable");
+ widgets->grp_toggle = yon_gtk_builder_get_widget(builder,"grp_toggle");
+ widgets->OptionsEntry = yon_gtk_builder_get_widget(builder,"OptionsEntry");
+ widgets->OptionsButton = yon_gtk_builder_get_widget(builder,"OptionsButton");
+ widgets->LayoutsTree = yon_gtk_builder_get_widget(builder,"LayoutsTree");
+ widgets->MoveUpButton = yon_gtk_builder_get_widget(builder,"MoveUpButton");
+ widgets->MoveDownButton = yon_gtk_builder_get_widget(builder,"MoveDownButton");
+ widgets->AddButton = yon_gtk_builder_get_widget(builder,"AddButton");
+ widgets->RemoveButton = yon_gtk_builder_get_widget(builder,"RemoveButton");
+ widgets->layoutsList = GTK_LIST_STORE(gtk_builder_get_object(builder,"liststore1"));
+ widgets->layoutsFilter = GTK_TREE_MODEL_FILTER(gtk_builder_get_object(builder,"LayoutsFilter"));
+ widgets->modelsList = GTK_LIST_STORE(gtk_builder_get_object(builder,"liststore2"));
+
+ int size;
+ GtkTreeIter iter;
+ config_str models = yon_config_load(get_models_command,&size);
+ for (int i=0;imodelsList,&iter);
+ gtk_list_store_set(widgets->modelsList,&iter,1,models[i],0,_(models[i+1]),-1);
+ }
+ main_config.layouts_list = gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_BOOLEAN);
+ int laysize;
+ config_str rtn = yon_resource_open_file(layouts_path,&size);
+ for (int i=0; iHeadInfoLabel,"head-text","label",YON_TYPE_STRING);
+
+ /* Signal connection | Присоединение сигналов */
+
+ g_signal_connect(G_OBJECT(widgets->AddButton),"clicked",G_CALLBACK(on_layouts_add),widgets);
+ g_signal_connect(G_OBJECT(widgets->RemoveButton),"clicked",G_CALLBACK(on_layouts_remove),widgets);
+ g_signal_connect(G_OBJECT(widgets->ModelCombo),"changed",G_CALLBACK(on_model_changed),widgets);
+ g_signal_connect(G_OBJECT(widgets->MoveDownButton),"clicked",G_CALLBACK(on_move_down),widgets);
+ g_signal_connect(G_OBJECT(widgets->MoveUpButton),"clicked",G_CALLBACK(on_move_up),widgets);
+ g_signal_connect(G_OBJECT(widgets->OptionsButton),"clicked",G_CALLBACK(on_options_open),widgets);
+ g_signal_connect(G_OBJECT(widgets->NumLockCombo),"changed",G_CALLBACK(on_num_lock_changed),widgets);
+ }
+
+ g_signal_connect(G_OBJECT(widgets->LoadLocalMenuItem),"activate",G_CALLBACK(on_config_local_load),widgets);
+ g_signal_connect(G_OBJECT(widgets->LoadGlobalMenuItem),"activate",G_CALLBACK(on_config_global_load),widgets);
+ g_signal_connect(G_OBJECT(widgets->LoadCustomMenuItem),"activate",G_CALLBACK(on_config_custom_load),widgets);
+
+ g_signal_connect(G_OBJECT(widgets->SaveMenuItem),"activate",G_CALLBACK(on_config_global_local_save),NULL);
+ g_signal_connect(G_OBJECT(widgets->SaveLocalMenuItem),"activate",G_CALLBACK(on_config_local_save),NULL);
+ g_signal_connect(G_OBJECT(widgets->SaveGlobalMenuItem),"activate",G_CALLBACK(on_config_global_save),NULL);
+ g_signal_connect(G_OBJECT(widgets->SaveCustomMenuItem),"activate",G_CALLBACK(on_config_custom_save),NULL);
+
+ yon_root_button_setup((template_main_window*)widgets,main_config.launch_arguments,main_config.launch_size);
+ yon_save_window_set_postsave_function(on_save_done,widgets);
+
+ on_config_local_load(NULL,widgets);
+}
+
+int main(int argc, char *argv[]){
+ setlocale(LC_ALL, "");
+ textdomain (LocaleName);
+
+ yon_ubl_connect_config((_template_config*)&main_config);
+ yon_ubl_window_init(TITLE_LABEL,TITLE_INFO_LABEL,LocaleName,CssPath,LocaleName,version_application,WIKI_LINK);
+ config_str unfound = NULL;
+ int size=0;
+ yon_ubl_setup_arguments(argc,argv,&unfound,&size,NULL);
+ gtk_init(&argc,&argv);
+ template_main_window *widgets = yon_ubl_window_setup();
+
+ //turn off if custom presented
+ // yon_ubl_settings_window_set_standard_callbacks(widgets,config_get_global_command,config_get_local_command,yon_config_get_custom_command("./"),config_get_default_command,config_get_global_only_parameters,config_get_local_only_parameters);
+
+ yon_main_window_complete((main_window*)widgets);
+ char *path = yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",LocaleName,"/",LocaleName,".conf",NULL);
+ yon_window_config_load(path);
+ main_config.launch_arguments=yon_char_parsed_copy(argv,argc);
+ main_config.launch_size=argc;
+ gtk_main();
+ return 0;
+}
\ No newline at end of file
diff --git a/source/ubl-settings-keyboard.h b/source/ubl-settings-keyboard.h
new file mode 100644
index 0000000..17eab8b
--- /dev/null
+++ b/source/ubl-settings-keyboard.h
@@ -0,0 +1,142 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef WEBKIT_FOUND
+ #include
+#endif
+#include "ubl-strings.h"
+
+#define _(String) gettext(String)
+
+
+
+#define glade_path "/com/ublinux/ui/ubl-settings-keyboard.glade"
+#define glade_layouts_path "/com/ublinux/ui/ubl-settings-keyboard-layouts.glade"
+#define glade_options_path "/com/ublinux/ui/ubl-settings-keyboard-options.glade"
+#define banner_path "/com/ublinux/images/ubl-settings-keyboard-banner.png"
+#define CssPath "/com/ublinux/css/ubl-settings-keyboard.css"
+#define config_path yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",LocaleName,"/",LocaleName,".conf",NULL)
+#define icon_path "com.ublinux.ubl-settings-keyboard"
+
+#define LocaleName "ubl-settings-keyboard"
+
+#define model_parameter "XKBMODEL"
+#define model_parameter_command "ubconfig --source global get keyboard XKBMODEL"
+#define keyboard_layout_parameter "XKBLAYOUT"
+#define keyboard_layout_parameter_command "ubconfig --source global get keyboard XKBLAYOUT"
+#define options_parameter "XKBOPTIONS"
+#define options_parameter_command "ubconfig --source global get keyboard XKBOPTIONS"
+#define num_lock_boot_parameter "NUMLOCK"
+#define num_lock_boot_parameter_command "ubconfig --source global get config NUMLOCK"
+
+#define yon_config_get_custom_command(target) yon_char_unite("ubconfig --source ",target," get config NUMLOCK; ubconfig --source ",target," get keyboard XKBMODEL XKBLAYOUT XKBOPTIONS",NULL)
+#define config_get_local_command "ubconfig --source system get config NUMLOCK; ubconfig --source global get keyboard XKBMODEL XKBLAYOUT XKBOPTIONS"
+#define config_get_global_command "ubconfig --source global get config NUMLOCK; ubconfig --source global get keyboard XKBMODEL XKBLAYOUT XKBOPTIONS"
+#define config_get_default_command ""
+
+#define config_get_global_only_parameters ""
+#define config_get_local_only_parameters ""
+
+
+#define get_options_command "grep -E \"grp:.*toggle|grp_led:.*toggle|compose:.*toggle\" /usr/share/X11/xkb/rules/base.lst|sed -e 's/^ *//g' -e 's/\t//g' -e 's/toggle */toggle;/g'"
+#define get_models_command "sed '/<\\/modelList>/q' /usr/share/X11/xkb/rules/base.xml | grep -E '^ {8,8}|^ {8,8}'|sed -e 's/ *//g' -e 's,,,g' -e 's/ *//g' -e 's,,,g'"
+#define layouts_path "resource:///com/ublinux/csv/layouts.csv"
+
+typedef char* string;
+
+__attribute__((unused)) static \
+string version_application;
+
+typedef struct {
+ template_config_fields
+ int save_config;
+ config_str launch_arguments;
+ int launch_size;
+ char *options;
+ GtkListStore *layouts_list;
+ GtkListStore *options_list;
+} config;
+
+typedef struct {
+ template_window_fields
+
+ GtkWidget *NumLockCombo;
+ GtkWidget *ModelCombo;
+ GtkWidget *keyboard;
+ GtkWidget *keytable;
+ GtkWidget *grp_toggle;
+ GtkWidget *OptionsEntry;
+ GtkWidget *OptionsButton;
+ GtkWidget *LayoutsTree;
+ GtkWidget *MoveUpButton;
+ GtkWidget *MoveDownButton;
+ GtkWidget *AddButton;
+ GtkWidget *RemoveButton;
+ GtkTreeModelFilter *layoutsFilter;
+ GtkListStore *layoutsList;
+ GtkListStore *modelsList;
+} main_window;
+
+
+typedef struct {
+ GtkWidget *Window;
+
+ GtkWidget *HatText;
+ GtkWidget *HeaderText;
+ GtkWidget *InfoText;
+ GtkWidget *AlwaysOpenCheck;
+
+ GtkWidget *CloseButton;
+ GtkWidget *AcceptButton;
+} documentation_confirmation_window;
+
+typedef struct {
+ GtkWidget *Window;
+ GtkWidget *MainTree;
+ GtkWidget *CancelButton;
+ GtkWidget *AcceptButton;
+ GtkListStore *list;
+} layouts_window;
+
+typedef struct {
+ GtkWidget *Window;
+ GtkWidget *CancelButton;
+ GtkWidget *AcceptButton;
+} options_window;
+
+void on_save_done(main_window *, config_str output, int size);
+void on_config_global_local_save(GtkWidget *, main_window *);
+void on_config_local_save(GtkWidget *, main_window *);
+void on_config_global_save(GtkWidget *, main_window *);
+void on_config_custom_save(GtkWidget *, main_window *);
+void on_config_local_load(GtkWidget *,main_window *);
+void on_config_global_load(GtkWidget *,main_window *);
+void on_config_custom_load(GtkWidget *,main_window *);
+
+void yon_load_proceed(YON_CONFIG_TYPE type);
+
+gboolean yon_interface_update(main_window *);
+
+void on_save_done(main_window *widgets, config_str output, int size);
+
+void config_init();
+
+void yon_main_window_complete(main_window *widgets);
+void on_move_down(GtkWidget *self, main_window *widgets);
+void on_move_up(GtkWidget *self, main_window *widgets);
+void on_layouts_add(GtkWidget *self, main_window *widgets);
+void on_layouts_accept(GtkWidget *self, dictionary *dict);
+void on_options_open(GtkWidget *self, main_window *widgets);
+void on_options_accept(GtkWidget *self, dictionary *dict);
+void on_model_changed(GtkComboBoxText *self, main_window *widgets);
+void on_num_lock_changed(GtkComboBox *self, main_window *widgets);
+void on_layouts_remove(GtkWidget *, main_window *widgets);
+void yon_layouts_save(main_window *widgets);
\ No newline at end of file
diff --git a/source/ubl-strings.h b/source/ubl-strings.h
new file mode 100644
index 0000000..21c8f9d
--- /dev/null
+++ b/source/ubl-strings.h
@@ -0,0 +1,20 @@
+#define WIKI_LINK _("https://wiki.ublinux.ru/ru/Программное_обеспечение/Программы_и_утилиты/Все/ubl-settings-keyboard")
+
+#define TITLE_LABEL _("Keyboard")
+#define TITLE_INFO_LABEL _("Keyboard configuration")
+
+#define CONSOLE_LABEL _("Console")
+#define NUM_LOCK_LABEL _("Num Lock on boot:")
+#define KEYBOARD_LABEL _("Keyboard")
+#define MODEL_LABEL _("Keyboard model:")
+#define OPTIONS_LABEL _("Keyboard options:")
+#define LAYOUTS_LABEL _("Keyboard layouts:")
+#define EDIT_LABEL _("Pick an option")
+#define MOVE_UP_LABEL _("Move layout up")
+#define MOVE_DOWN_LABEL _("Move layout down")
+#define ADD_LABEL _("Add layout")
+#define REMOVE_LABEL _("Remove layout")
+#define DEFAULT_LABEL _("Default")
+#define ON_LABEL _("On")
+#define OFF_LABEL _("Off")
+#define ACCEPT_LABEL _("Accept")
\ No newline at end of file
diff --git a/ubl-settings-keyboard-layouts.glade b/ubl-settings-keyboard-layouts.glade
new file mode 100644
index 0000000..29604eb
--- /dev/null
+++ b/ubl-settings-keyboard-layouts.glade
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
diff --git a/ubl-settings-keyboard-options.glade b/ubl-settings-keyboard-options.glade
new file mode 100644
index 0000000..d9d8518
--- /dev/null
+++ b/ubl-settings-keyboard-options.glade
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+ 450
+ 550
+ True
+ False
+ dialog
+
+
+ False
+ 3
+ 3
+ 3
+ 3
+ vertical
+ 5
+
+
+ False
+ end
+
+
+ Cancel
+ True
+ True
+ True
+ image2
+
+
+ True
+ True
+ 0
+
+
+
+
+ Accept
+ True
+ True
+ True
+ image1
+
+
+ True
+ True
+ 1
+
+
+
+
+ False
+ False
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+ emblem-ok-symbolic
+
+
+ True
+ False
+ process-stop-symbolic
+
+
diff --git a/ubl-settings-keyboard.css b/ubl-settings-keyboard.css
new file mode 100644
index 0000000..88e8c57
--- /dev/null
+++ b/ubl-settings-keyboard.css
@@ -0,0 +1,114 @@
+
+.thin {
+ margin:0px;
+ padding:0px;
+}
+.noborder {
+ border:none;
+}
+.nobackground {
+background:transparent;
+}
+.nobackground:active {
+background:transparent;
+}
+.textHead{
+ text-shadow: 2px 2px @theme_bg_color;
+ color: @theme_text_color;
+}
+
+.inherited>* {
+ border:none;
+ background:inherit;
+}
+.workingbg {
+ background:@theme_base_color;
+}
+.menuitembottom{
+ margin-top:0px;
+ margin-bottom:3px;
+ border-color:inherit;
+ border-left-width:inherit;
+ border-right-width:inherit;
+ }
+ .menuitemmiddle{
+ margin-top:0px;
+ margin-bottom:0px;
+ border-color:inherit;
+ border-left-width:inherit;
+ border-right-width:inherit;
+ }
+
+ .menuitemtop{
+ margin-bottom:0px;
+ border-color:inherit;
+ border-top-width:inherit;
+ border-left-width:inherit;
+ border-right-width:inherit;
+ }
+ .menuitemtop>*{
+ margin:2px 2px 0 2px;
+ padding: 3px 10px 3px 5px;
+ /* padding: 5px 0px 3px 5px; */
+ border:transparent;
+ }
+ .menuitemmiddle>*{
+ margin:0 2px 0 2px;
+ padding: 3px 10px 3px 5px;
+ /* padding: 3px 0px 3px 5px; */
+ border:transparent;
+ }
+ .menuitembottom>*{
+ margin:0 2px 2px 2px;
+ padding: 3px 10px 3px 5px;
+ /* padding: 3px 0px 5px 5px; */
+ }
+ .menuitemtop:hover {
+ background:@theme_bg_color;
+ border-color:inherit;
+ border-top-width:inherit;
+ border-left-width:inherit;
+ border-right-width:inherit;
+ }
+ .menuitemmiddle:hover {
+ background:@theme_bg_color;
+ border-color:inherit;
+ border-left-width:inherit;
+ border-right-width:inherit;
+ }
+ .menuitembottom:hover {
+ background:@theme_bg_color;
+ border-color:inherit;
+ border-bottom-width:0px;
+ border-left-width:inherit;
+ border-right-width:inherit;
+
+ }
+ .menuitemtop:hover>* {
+ margin:2px 2px 0 2px;
+ padding: 3px 10px 3px 5px;
+ /* padding: 5px 0 3px 5px; */
+ background:@theme_selected_bg_color;
+ border-radius:2px;
+ }
+ .menuitemmiddle:hover>* {
+ margin:0 2px 0px 2px;
+ padding: 3px 10px 3px 5px;
+ /* padding: 3px 0px 3px 5px; */
+ background:@theme_selected_bg_color;
+ border-radius:2px;
+ }
+ .menuitembottom:hover>* {
+ margin:0 2px 2px 2px;
+ padding: 3px 10px 3px 5px;
+ /* padding: 3px 0px 5px 5px; */
+ background:@theme_selected_bg_color;
+ border-radius:2px;
+ }
+ .boxInfoMessError{
+ background-color: #ea9999;
+}
+
+.boxInfoMessOK{
+ background-color: #f3f0ac;
+}
\ No newline at end of file
diff --git a/ubl-settings-keyboard.desktop b/ubl-settings-keyboard.desktop
new file mode 100644
index 0000000..36694f1
--- /dev/null
+++ b/ubl-settings-keyboard.desktop
@@ -0,0 +1,15 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Keyboard configuration
+Name[ru]=Клавиатура
+GenericName=ubl-settings-keyboard
+GenericName[ru]=Клавиатура
+Comment=Keyboard configuration
+Comment[ru]=Настройки клавиатуры
+Type=Application
+Exec=pkexec ubl-settings-keyboard
+Icon=com.ublinux.ubl-settings-keyboard
+Terminal=false
+X-XfcePluggable=true
+X-UBLPluggable=true
+Categories=XFCE;GTK;X-UBL-SettingsManager;X-UBL-Personal-Settings;
diff --git a/ubl-settings-keyboard.glade b/ubl-settings-keyboard.glade
new file mode 100644
index 0000000..3445b85
--- /dev/null
+++ b/ubl-settings-keyboard.glade
@@ -0,0 +1,587 @@
+
+
+
+
+
+
+
+
+
+ True
+ False
+ user-trash-symbolic
+
+
+ True
+ False
+ value-increase-symbolic
+
+
+ True
+ False
+ document-edit-symbolic
+
+
+
+
+
+
+
+
+
+
+
+
+ liststore1
+
+
+
+
+
+
+
+
+
+
+ Default
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+ 5
+ 5
+ 5
+ 5
+ 5
+ 5
+ True
+ True
+ vertical
+ 5
+
+
+ True
+ False
+ 0.019999999552965164
+ in
+
+
+ True
+ False
+ 5
+ 5
+ 5
+
+
+ True
+ False
+ 5
+
+
+ True
+ False
+ Num Lock on boot:
+ 0
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+ 0
+
+ - Default
+ - On
+ - Off
+
+
+
+ True
+ True
+ 1
+
+
+
+
+
+
+
+
+ True
+ False
+ Console
+
+
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+ 0.019999999552965164
+ in
+
+
+ True
+ False
+ 5
+ 5
+ 5
+
+
+ True
+ False
+ vertical
+ 6
+
+
+ True
+ False
+ 5
+
+
+ True
+ False
+ Keyboard model:
+ 0
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+ liststore2
+ 0
+ 1
+
+
+
+ 0
+
+
+
+
+ True
+ True
+ 1
+
+
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+ 5
+
+
+ True
+ False
+ vertical
+ 5
+
+
+ True
+ True
+ in
+
+
+ True
+ True
+ LayoutsFilter
+ False
+
+
+ column
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ True
+ True
+ 0
+
+
+
+
+ True
+ True
+ 0
+
+
+
+
+ True
+ False
+ vertical
+ 5
+
+
+ True
+ True
+ True
+ Move layout up
+
+
+
+
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ True
+ True
+ Move layout down
+
+
+
+
+
+
+ False
+ True
+ 1
+
+
+
+
+ True
+ True
+ True
+ Добавить раскладку
+ image3
+
+
+
+ False
+ True
+ 2
+
+
+
+
+ True
+ True
+ True
+ Удалить раскладку
+ image1
+
+
+
+ False
+ True
+ 4
+
+
+
+
+ False
+ True
+ 1
+
+
+
+
+ True
+ True
+ end
+ 2
+
+
+
+
+ True
+ False
+ Keyboard layouts:
+ 0
+
+
+ False
+ True
+ end
+ 4
+
+
+
+
+ False
+ 5
+
+
+ True
+ False
+ KEYBOARD:
+ 0
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ True
+
+
+ True
+ True
+ 1
+
+
+
+
+ False
+ True
+ 4
+
+
+
+
+ True
+ False
+ 5
+
+
+ True
+ False
+ Keyboard options:
+ 0
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+
+
+ True
+ True
+ 1
+
+
+
+
+ True
+ True
+ True
+ Pick an option
+ image4
+
+
+
+ False
+ True
+ 2
+
+
+
+
+ False
+ True
+ 7
+
+
+
+
+
+
+
+
+ True
+ False
+ Keyboard
+
+
+
+
+ True
+ True
+ 3
+
+
+
+
+
+
+
+
+
+
+
+