diff options
| -rw-r--r-- | .build.yml | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | debian/control | 3 | ||||
| -rw-r--r-- | po/es.po | 12 | ||||
| -rw-r--r-- | po/fi.po | 26 | ||||
| -rw-r--r-- | po/hr.po | 17 | ||||
| -rw-r--r-- | po/lo.po | 11 | ||||
| -rw-r--r-- | po/nb.po | 12 | ||||
| -rw-r--r-- | po/oc.po | 10 | ||||
| -rw-r--r-- | po/tr.po | 10 | ||||
| -rw-r--r-- | po/zh_CN.po | 12 | ||||
| -rw-r--r-- | src/keyboard-lomiri.c | 416 | ||||
| -rw-r--r-- | src/keyboard-x11.c | 30 | ||||
| -rw-r--r-- | src/keyboard.h | 12 | ||||
| -rw-r--r-- | src/service.c | 197 |
15 files changed, 672 insertions, 102 deletions
@@ -18,6 +18,7 @@ requires: - libxklavier - libxkbcommon - accountsservice + - systemd-libs # - libayatana-common debian: @@ -37,6 +38,7 @@ requires: - libxkbregistry-dev - libaccountsservice-dev - systemd + - libudev-dev # - libayatana-common-dev # For building libayatana-common: - liblomiri-url-dispatcher-dev @@ -54,6 +56,7 @@ requires: - libxklavier-dev - libaccountsservice-dev - systemd + - libudev-dev # - libayatana-common-dev # - libxkbcommon-dev # - libxkbregistry-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 37de3115..30fed304 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,8 @@ add_definitions (-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}" -DLOCALEDIR="${CMAKE_INS find_package (PkgConfig REQUIRED) include (CheckIncludeFile) include (FindPkgConfig) -pkg_check_modules(SERVICE_DEPS REQUIRED glib-2.0>=2.36 gio-2.0>=2.36 libayatana-common>=0.9.11 accountsservice xkbcommon>=1.0.3 xkbregistry>=1.0.3) + +pkg_check_modules(SERVICE_DEPS REQUIRED glib-2.0>=2.36 gio-2.0>=2.36 libayatana-common>=0.9.11 accountsservice xkbcommon>=1.0.3 xkbregistry>=1.0.3 libudev) pkg_check_modules(X11_DEPS REQUIRED x11>=1.6.5 libxklavier>=5.3) include_directories (SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS}) diff --git a/debian/control b/debian/control index 1bc2b27e..82f08630 100644 --- a/debian/control +++ b/debian/control @@ -11,6 +11,7 @@ Build-Depends: cmake, libxkbcommon-dev (>=1.0.3), libxkbregistry-dev (>=1.0.3), libaccountsservice-dev, + libudev-dev, # for packaging debhelper (>= 10), dh-systemd | hello, @@ -28,7 +29,7 @@ Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ayatana-indicator-common, - matekbd-keyboard-display | gkbd-capplet, + matekbd-keyboard-display | gkbd-capplet | tecla, Description: Ayatana Indicator Keyboard Applet This package contains the keyboard indicator, which should show as an icon in the top panel of indicator aware destkop environments. @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2023-09-16 20:12+0000\n" -"Last-Translator: gallegonovato <fran-carro@hotmail.es>\n" -"Language-Team: Spanish <https://hosted.weblate.org/projects/ayatana-" -"indicators/keyboard-applet/es/>\n" +"PO-Revision-Date: 2025-06-30 03:06+0000\n" +"Last-Translator: DP <dprietob@users.noreply.hosted.weblate.org>\n" +"Language-Team: Spanish <https://hosted.weblate.org/projects/" +"ayatana-indicators/keyboard-applet/es/>\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.0.2\n" +"X-Generator: Weblate 5.13-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." @@ -53,7 +53,7 @@ msgstr "Disposición de teclado actual" #: src/service.c:193 msgid "Always show OSK" -msgstr "" +msgstr "Mostrar siempre OSK" #: src/service.c:199 msgid "Keyboard Settings…" @@ -8,34 +8,36 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2021-02-20 01:50+0000\n" -"Last-Translator: J. Lavoie <j.lavoie@net-c.ca>\n" -"Language-Team: Finnish <https://hosted.weblate.org/projects/ayatana-" -"indicators/keyboard-applet/fi/>\n" +"PO-Revision-Date: 2025-07-18 20:08+0000\n" +"Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n" +"Language-Team: Finnish <https://hosted.weblate.org/projects/" +"ayatana-indicators/keyboard-applet/fi/>\n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.5\n" +"X-Generator: Weblate 5.13-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." -msgstr "" +msgstr "Näytä kielikuvake työpöytätilassa." #: data/org.ayatana.indicator.keyboard.gschema.xml:2 msgid "" "If enabled, the indicator shows the current layout icon. Otherwise, it " "displays a generic keyboard icon." msgstr "" +"Jos käytössä, ilmaisin näyttää nykyisen asettelun kuvakkeen. Muussa " +"tapauksessa se näyttää yleisen näppäimistökuvakkeen." #: data/org.ayatana.indicator.keyboard.gschema.xml:3 msgid "Show the language icon in phone mode." -msgstr "" +msgstr "Näytä kielikuvake puhelintilassa." #: data/org.ayatana.indicator.keyboard.gschema.xml:4 msgid "Show the language icon in the greeter." -msgstr "" +msgstr "Näytä kielikuvake tervehdysikkunassa." #: src/service.c:95 msgid "Keyboard" @@ -43,7 +45,7 @@ msgstr "Näppäimistö" #: src/service.c:96 msgid "Keyboard layout switcher and settings" -msgstr "" +msgstr "Näppäimistöasettelun vaihtaja ja asetukset" #: src/service.c:133 msgid "Current keyboard layout" @@ -51,14 +53,12 @@ msgstr "Nykyinen näppäimistöasettelu" #: src/service.c:193 msgid "Always show OSK" -msgstr "" +msgstr "Näytä aina OSK" #: src/service.c:199 -#, fuzzy msgid "Keyboard Settings…" msgstr "Näppäimistön asetukset…" #: src/service.c:207 -#, fuzzy msgid "Show Current Layout" -msgstr "Nykyinen näppäimistöasettelu" +msgstr "Näytä nykyinen asettelu" @@ -8,17 +8,17 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2023-05-21 13:53+0000\n" +"PO-Revision-Date: 2025-09-15 20:01+0000\n" "Last-Translator: Milo Ivir <mail@milotype.de>\n" -"Language-Team: Croatian <https://hosted.weblate.org/projects/ayatana-" -"indicators/keyboard-applet/hr/>\n" +"Language-Team: Croatian <https://hosted.weblate.org/projects/" +"ayatana-indicators/keyboard-applet/hr/>\n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.18-dev\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.14-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." @@ -54,13 +54,12 @@ msgstr "Trenutačni raspored tipkovnice" #: src/service.c:193 msgid "Always show OSK" -msgstr "" +msgstr "Uvijek prikaži ekransku tipkovnicu" #: src/service.c:199 msgid "Keyboard Settings…" msgstr "Postavke tipkovnice …" #: src/service.c:207 -#, fuzzy msgid "Show Current Layout" -msgstr "Trenutačni raspored tipkovnice" +msgstr "Prikaži trenutačni raspored" @@ -8,13 +8,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2021-01-22 23:28+0100\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" +"PO-Revision-Date: 2025-11-15 03:51+0000\n" +"Last-Translator: BoneNI <bounkirdni@gmail.com>\n" +"Language-Team: Lao <https://hosted.weblate.org/projects/ayatana-indicators/" +"keyboard-applet/lo/>\n" "Language: lo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.15-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." @@ -36,7 +39,7 @@ msgstr "" #: src/service.c:95 msgid "Keyboard" -msgstr "" +msgstr "ແປ້ນພິມ" #: src/service.c:96 msgid "Keyboard layout switcher and settings" @@ -8,20 +8,20 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2021-02-23 16:50+0000\n" -"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" -"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/ayatana-" -"indicators/keyboard-applet/nb_NO/>\n" +"PO-Revision-Date: 2025-08-26 19:02+0000\n" +"Last-Translator: Ida Brenna <ida@larald.no>\n" +"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/" +"ayatana-indicators/keyboard-applet/nb_NO/>\n" "Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.5\n" +"X-Generator: Weblate 5.13\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." -msgstr "" +msgstr "Vis språkikonet i skrivebordsmodus." #: data/org.ayatana.indicator.keyboard.gschema.xml:2 msgid "" @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2023-10-16 04:08+0000\n" +"PO-Revision-Date: 2025-10-06 16:02+0000\n" "Last-Translator: Quentin PAGÈS <quentinantonin@free.fr>\n" -"Language-Team: Occitan <https://hosted.weblate.org/projects/ayatana-" -"indicators/keyboard-applet/oc/>\n" +"Language-Team: Occitan <https://hosted.weblate.org/projects/" +"ayatana-indicators/keyboard-applet/oc/>\n" "Language: oc\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.1-dev\n" +"X-Generator: Weblate 5.14-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." @@ -53,7 +53,7 @@ msgstr "Agençament actual del clavièr" #: src/service.c:193 msgid "Always show OSK" -msgstr "" +msgstr "Totjorn afichar lo clavièr virtual" #: src/service.c:199 msgid "Keyboard Settings…" @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2023-09-16 20:12+0000\n" +"PO-Revision-Date: 2025-10-05 14:01+0000\n" "Last-Translator: Oğuz Ersen <oguz@ersen.moe>\n" -"Language-Team: Turkish <https://hosted.weblate.org/projects/ayatana-" -"indicators/keyboard-applet/tr/>\n" +"Language-Team: Turkish <https://hosted.weblate.org/projects/" +"ayatana-indicators/keyboard-applet/tr/>\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.0.2\n" +"X-Generator: Weblate 5.14-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." @@ -53,7 +53,7 @@ msgstr "Geçerli klavye düzeni" #: src/service.c:193 msgid "Always show OSK" -msgstr "" +msgstr "Her zaman ekran klavyesini göster" #: src/service.c:199 msgid "Keyboard Settings…" diff --git a/po/zh_CN.po b/po/zh_CN.po index 2145dfbc..953cb744 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-23 19:05+0100\n" -"PO-Revision-Date: 2024-04-01 22:37+0000\n" -"Last-Translator: 复予 <clonewith@qq.com>\n" -"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" -"ayatana-indicators/keyboard-applet/zh_Hans/>\n" +"PO-Revision-Date: 2025-07-13 05:01+0000\n" +"Last-Translator: \"Alioc.\" <hit.177411245@gmail.com>\n" +"Language-Team: Chinese (Simplified Han script) <https://hosted.weblate.org/" +"projects/ayatana-indicators/keyboard-applet/zh_Hans/>\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.5-dev\n" +"X-Generator: Weblate 5.13-dev\n" #: data/org.ayatana.indicator.keyboard.gschema.xml:1 msgid "Show the language icon in desktop mode." @@ -51,7 +51,7 @@ msgstr "当前键盘布局" #: src/service.c:193 msgid "Always show OSK" -msgstr "" +msgstr "总是显示 OSK" #: src/service.c:199 msgid "Keyboard Settings…" diff --git a/src/keyboard-lomiri.c b/src/keyboard-lomiri.c index c00bc55a..176d576b 100644 --- a/src/keyboard-lomiri.c +++ b/src/keyboard-lomiri.c @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 Robert Tari <robert@tari.in> + * Copyright 2021-2025 Robert Tari <robert@tari.in> * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published @@ -17,10 +17,37 @@ #include <act/act.h> #include <xkbcommon/xkbregistry.h> #include <glib-object.h> +#include <libudev.h> #include "languages.h" #include "keyboard.h" #include "system-layouts.h" +gchar *LOMIRI_TO_ISO[][2] = +{ + {"ar", "ara"}, + {"bn", "bd"}, + {"bn-probhat", "bd+probhat"}, + {"bs", "ba"}, + {"cs", "cz"}, + {"da", "dk"}, + {"el", "gr"}, + {"en", "us"}, + {"endv", "us+dvorak"}, + {"eo", "epo"}, + {"fa", "ir"}, + {"fr-ch", "ch+fr"}, + {"gd", "gb+gla"}, + {"he", "il"}, + {"ja", "jp"}, + {"ko", "kr"}, + {"nb", "no"}, + {"sl", "si"}, + {"sr", "rs"}, + {"sv", "se"}, + {"uk", "ua"}, + {NULL, NULL} +}; + enum { LAYOUT_CHANGED, @@ -34,9 +61,18 @@ struct _KeyboardPrivate { GHashTable *lLayouts; guint nLayout; + guint nLayoutOSK; GSList *lLayoutRec; + GSList *lLayoutRecOSK; GSList *lUsers; GSettings *pSettings; + struct udev *pUdev; + struct udev_monitor *pMonitor; + GIOChannel *pChannel; + gboolean bHardwareKeyboard; + gboolean bSoftwareKeyboard; + GSettings *pLomiriSettings; + GSettings *pMaliitSettings; }; typedef KeyboardPrivate priv_t; @@ -169,24 +205,57 @@ void keyboard_AddSource(Keyboard *pKeyboard) return; } -guint keyboard_GetNumLayouts(Keyboard *pKeyboard) +guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK) { - return g_slist_length (pKeyboard->pPrivate->lLayoutRec); + guint nLayouts = 0; + + if (bOSK) + { + nLayouts = g_slist_length (pKeyboard->pPrivate->lLayoutRecOSK); + } + else + { + nLayouts = g_slist_length (pKeyboard->pPrivate->lLayoutRec); + } + + return nLayouts; } -guint keyboard_GetLayoutIndex (Keyboard *pKeyboard) +guint keyboard_GetLayoutIndex (Keyboard *pKeyboard, gboolean bOSK) { - return pKeyboard->pPrivate->nLayout; + if (bOSK) + { + return pKeyboard->pPrivate->nLayoutOSK; + } + else + { + return pKeyboard->pPrivate->nLayout; + } } -void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription) +void keyboard_GetLayout(Keyboard *pKeyboard, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId) { - if (nLayout == -1) + + GSList *lLayoutRec = NULL; + + if (bOSK) + { + if (nLayout == -1) + { + nLayout = pKeyboard->pPrivate->nLayoutOSK; + } + lLayoutRec = pKeyboard->pPrivate->lLayoutRecOSK; + } + else { - nLayout = pKeyboard->pPrivate->nLayout; + if (nLayout == -1) + { + nLayout = pKeyboard->pPrivate->nLayout; + } + lLayoutRec = pKeyboard->pPrivate->lLayoutRec; } - gchar *sLayout = g_slist_nth_data (pKeyboard->pPrivate->lLayoutRec, nLayout); + gchar *sLayout = g_slist_nth_data (lLayoutRec, nLayout); const Layout *pLayout; g_hash_table_lookup_extended(pKeyboard->pPrivate->lLayouts, sLayout, NULL, (gpointer*)&pLayout); @@ -199,9 +268,14 @@ void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gc { *pDescription = g_strdup(pLayout->sDescription); } + + if (pId != NULL) + { + *pId = g_strdup (sLayout); + } } -void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout) +void keyboard_SetLayoutHardware(Keyboard *pKeyboard, gint nLayout) { if (isGreeter() == FALSE) { @@ -293,11 +367,103 @@ void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout) } } +void keyboard_SetLayoutSoftware(Keyboard *pKeyboard, gint nLayout) +{ + if (isGreeter() == FALSE) + { + gchar *sId = g_slist_nth_data (pKeyboard->pPrivate->lLayoutRecOSK, nLayout); + guint nId = 0; + gchar *sLayoutOSK = NULL; + + while (LOMIRI_TO_ISO[nId][0] != NULL) + { + gboolean bEqual = g_str_equal (LOMIRI_TO_ISO[nId][1], sId); + + if (bEqual) + { + sLayoutOSK = LOMIRI_TO_ISO[nId][0]; + + break; + } + + nId++; + } + + if (!sLayoutOSK) + { + sLayoutOSK = sId; + } + + guint nEnabledLayoutsOSK = g_slist_length (pKeyboard->pPrivate->lLayoutRecOSK); + + GVariantBuilder cLayoutsOSKBuilder; + g_variant_builder_init (&cLayoutsOSKBuilder, G_VARIANT_TYPE ("as")); + if (sLayoutOSK) + { + g_variant_builder_add (&cLayoutsOSKBuilder, "s", sLayoutOSK); + } + + for (guint nLayout = 0; nLayout < nEnabledLayoutsOSK; nLayout++) + { + gchar *sIdIso = g_slist_nth_data (pKeyboard->pPrivate->lLayoutRecOSK, nLayout); + + nId = 0; + gchar *sIdLomiri = NULL; + while (LOMIRI_TO_ISO[nId][0] != NULL) + { + gboolean bEqual = g_str_equal (LOMIRI_TO_ISO[nId][1], sIdIso); + + if (bEqual) + { + sIdLomiri = LOMIRI_TO_ISO[nId][0]; + + break; + } + + nId++; + } + if (!sIdLomiri) + { + sIdLomiri = sIdIso; + } + + if (strcmp(sIdLomiri, sLayoutOSK)) + { + g_variant_builder_add (&cLayoutsOSKBuilder, "s", sIdLomiri); + } + } + GVariant *pEnabledLayoutsOSK = g_variant_builder_end (&cLayoutsOSKBuilder); + + g_settings_set_string (pKeyboard->pPrivate->pMaliitSettings, "active-language", sLayoutOSK); + g_settings_set_value (pKeyboard->pPrivate->pMaliitSettings, "enabled-languages", pEnabledLayoutsOSK); + } + else + { + // TODO + } +} + +void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout, gboolean bOSK) +{ + if (bOSK) + { + keyboard_SetLayoutSoftware(pKeyboard, nLayout); + } + else + { + keyboard_SetLayoutHardware(pKeyboard, nLayout); + } +} + static void onDispose(GObject *pObject) { Keyboard *self = G_KEYBOARD(pObject); g_signal_handlers_disconnect_by_data (self->pPrivate->pSettings, self); g_clear_object (&self->pPrivate->pSettings); + g_signal_handlers_disconnect_by_data (self->pPrivate->pLomiriSettings, self); + g_clear_object (&self->pPrivate->pLomiriSettings); + g_signal_handlers_disconnect_by_data (self->pPrivate->pMaliitSettings, self); + g_clear_object (&self->pPrivate->pMaliitSettings); if (self->pPrivate->lLayouts) { @@ -309,11 +475,31 @@ static void onDispose(GObject *pObject) g_slist_free_full(self->pPrivate->lLayoutRec, g_free); } + if (self->pPrivate->lLayoutRecOSK) + { + g_slist_free_full (self->pPrivate->lLayoutRecOSK, g_free); + } + if (self->pPrivate->lUsers) { g_slist_free(self->pPrivate->lUsers); } + if (self->pPrivate->pChannel) + { + g_io_channel_unref (self->pPrivate->pChannel); + } + + if (self->pPrivate->pMonitor) + { + udev_monitor_unref (self->pPrivate->pMonitor); + } + + if (self->pPrivate->pUdev) + { + udev_unref (self->pPrivate->pUdev); + } + G_OBJECT_CLASS(keyboard_parent_class)->dispose(pObject); } @@ -371,10 +557,150 @@ static void onSourcesChanged (GSettings *pSettings, const gchar *sKey, gpointer } } +static void onSoftwareKeyboardEnabled (GSettings *pSettings, const gchar *sKey, gpointer pData) +{ + Keyboard *self = G_KEYBOARD (pData); + self->pPrivate->bSoftwareKeyboard = g_settings_get_boolean (pSettings, "always-show-osk"); + g_signal_emit (self, m_lSignals[CONFIG_CHANGED], 0); + g_signal_emit (self, m_lSignals[LAYOUT_CHANGED], 0); +} + +static void onSoftwareLayoutChanged (GSettings *pSettings, const gchar *sKey, gpointer pData) +{ + Keyboard *pKeyboard = G_KEYBOARD (pData); + g_signal_emit (pKeyboard, m_lSignals[LAYOUT_CHANGED], 0); +} + +static void onSoftwareLayoutsChanged (GSettings *pSettings, const gchar *sKey, gpointer pData) +{ + Keyboard *pKeyboard = G_KEYBOARD (pData); + gboolean bsignal = FALSE; + + if (pKeyboard->pPrivate->lLayoutRecOSK) + { + g_slist_free_full (g_steal_pointer (&pKeyboard->pPrivate->lLayoutRecOSK), g_free); + bsignal = TRUE; + } + + GStrv lLayouts = g_settings_get_strv (pSettings, "enabled-languages"); + guint nLayouts = g_strv_length (lLayouts); + + if (lLayouts) + { + for (guint nLayout = 0; nLayout < nLayouts; nLayout++) + { + guint nId = 0; + gchar *sLayout = NULL; + + while (LOMIRI_TO_ISO[nId][0] != NULL) + { + gboolean bEqual = g_str_equal (LOMIRI_TO_ISO[nId][0], lLayouts[nLayout]); + + if (bEqual) + { + sLayout = g_strdup (LOMIRI_TO_ISO[nId][1]); + + break; + } + + nId++; + } + + if (!sLayout) + { + sLayout = g_strdup (lLayouts[nLayout]); + } + + pKeyboard->pPrivate->lLayoutRecOSK = g_slist_append (pKeyboard->pPrivate->lLayoutRecOSK, sLayout); + } + + g_strfreev (lLayouts); + } + + if (bsignal) + { + g_signal_emit (pKeyboard, m_lSignals[CONFIG_CHANGED], 0); + g_signal_emit (pKeyboard, m_lSignals[LAYOUT_CHANGED], 0); + } +} + +static bool udevDeviceIsHardwareKeyboard (struct udev_device *pDevice) +{ + const gchar *sValue = udev_device_get_property_value (pDevice, "ID_INPUT_KEYBOARD"); + gint nCompared = g_strcmp0 (sValue, "1"); + + return nCompared == 0; +} + +static gboolean udevHasHardwareKeyboard (struct udev *pUdev) +{ + struct udev_enumerate *pEnumerate = udev_enumerate_new (pUdev); + udev_enumerate_add_match_subsystem (pEnumerate, "input"); + udev_enumerate_scan_devices (pEnumerate); + struct udev_list_entry *lEntries = udev_enumerate_get_list_entry (pEnumerate); + struct udev_list_entry *pEntry; + gboolean bFound = FALSE; + + udev_list_entry_foreach (pEntry, lEntries) + { + const gchar *sPath = udev_list_entry_get_name (pEntry); + struct udev_device *pDevice = udev_device_new_from_syspath (pUdev, sPath); + gboolean bKeyboard = udevDeviceIsHardwareKeyboard (pDevice); + + if (bKeyboard) + { + bFound = TRUE; + udev_device_unref (pDevice); + + break; + } + + udev_device_unref (pDevice); + } + + udev_enumerate_unref (pEnumerate); + + return bFound; +} + +static gboolean onUdevEvent (GIOChannel *pChannel, GIOCondition nCondition, gpointer pData) +{ + Keyboard *self = G_KEYBOARD (pData); + struct udev_device *pDevice = udev_monitor_receive_device (self->pPrivate->pMonitor); + + if (pDevice) + { + gboolean bKeyboard = udevDeviceIsHardwareKeyboard (pDevice); + + if (bKeyboard) + { + struct udev *pUdev = udev_device_get_udev (pDevice); + self->pPrivate->bHardwareKeyboard = udevHasHardwareKeyboard (pUdev); + g_signal_emit (self, m_lSignals[CONFIG_CHANGED], 0); + g_signal_emit (self, m_lSignals[LAYOUT_CHANGED], 0); + } + + udev_device_unref (pDevice); + } + + return TRUE; +} + +gboolean keyboard_hasHardwareKeyboard (Keyboard *self) +{ + return self->pPrivate->bHardwareKeyboard; +} + +gboolean keyboard_hasSoftwareKeyboard (Keyboard *self) +{ + return self->pPrivate->bSoftwareKeyboard; +} + static void keyboard_init(Keyboard *self) { self->pPrivate = keyboard_get_instance_private(self); self->pPrivate->lLayoutRec = NULL; + self->pPrivate->lLayoutRecOSK = NULL; self->pPrivate->lLayouts = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, freeLayout); // Read all available layouts @@ -422,6 +748,27 @@ static void keyboard_init(Keyboard *self) rxkb_context_unref(pContext); + self->pPrivate->nLayoutOSK = 0; + + // Lomiri-specific layouts + const gchar *LAYOUTS[][3] = + { + {"emoji", "emoji", "Emoji"}, + {"Bn", "bn-avro", "Bangla (Avro)"}, + {"Zn", "chewing", "Chinese (Chewing)"}, + {"Zn", "pinyin", "Chinese (Pinyin)"} + }; + + for (guint nLayout = 0; nLayout < 3; nLayout++) + { + Layout *pLayout = g_slice_new0 (Layout); + pLayout->sId = g_strdup (LAYOUTS[nLayout][1]); + pLayout->sLanguage = g_strdup (LAYOUTS[nLayout][0]); + pLayout->sDescription = g_strdup (LAYOUTS[nLayout][2]); + g_hash_table_replace (self->pPrivate->lLayouts, pLayout->sId, pLayout); + } + //~Lomiri-specific layouts + if (isGreeter() == FALSE) { self->pPrivate->nLayout = 0; @@ -492,4 +839,53 @@ static void keyboard_init(Keyboard *self) g_signal_connect_object(pManager, "notify::is-loaded", G_CALLBACK(onManagerLoaded), self, G_CONNECT_SWAPPED); } } + + // Watch for a hardware keyboard + self->pPrivate->pUdev = udev_new (); + self->pPrivate->pMonitor = udev_monitor_new_from_netlink (self->pPrivate->pUdev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype (self->pPrivate->pMonitor, "input", NULL); + udev_monitor_enable_receiving (self->pPrivate->pMonitor); + gint nFd = udev_monitor_get_fd (self->pPrivate->pMonitor); + self->pPrivate->bHardwareKeyboard = udevHasHardwareKeyboard (self->pPrivate->pUdev); + self->pPrivate->pChannel = g_io_channel_unix_new (nFd); + g_io_add_watch (self->pPrivate->pChannel, G_IO_IN, onUdevEvent, self); + //~Watch for a hardware keyboard + + // Watch software keyboard + GSettingsSchemaSource *pSource = g_settings_schema_source_get_default (); + GSettingsSchema *pSchema = NULL; + + if (pSource) + { + pSchema = g_settings_schema_source_lookup (pSource, "com.lomiri.Shell", FALSE); + + if (pSchema) + { + g_settings_schema_unref (pSchema); + self->pPrivate->pLomiriSettings = g_settings_new ("com.lomiri.Shell"); + g_signal_connect (self->pPrivate->pLomiriSettings, "changed::always-show-osk", G_CALLBACK (onSoftwareKeyboardEnabled), self); + onSoftwareKeyboardEnabled (self->pPrivate->pLomiriSettings, "always-show-osk", self); + } + else + { + g_error ("Panic: no com.lomiri.Shell schema found"); + } + + pSchema = g_settings_schema_source_lookup (pSource, "com.lomiri.keyboard.maliit", FALSE); + + if (pSchema) + { + g_settings_schema_unref (pSchema); + self->pPrivate->pMaliitSettings = g_settings_new ("com.lomiri.keyboard.maliit"); + g_signal_connect (self->pPrivate->pMaliitSettings, "changed::enabled-languages", G_CALLBACK (onSoftwareLayoutsChanged), self); + onSoftwareLayoutsChanged (self->pPrivate->pMaliitSettings, "enabled-languages", self); + g_signal_connect (self->pPrivate->pMaliitSettings, "changed::active-language", G_CALLBACK (onSoftwareLayoutChanged), self); + onSoftwareLayoutChanged (self->pPrivate->pMaliitSettings, "active-language", self); + } + else + { + g_error ("Panic: no com.lomiri.keyboard.maliit schema found"); + } + } + //~Watch software keyboard } diff --git a/src/keyboard-x11.c b/src/keyboard-x11.c index d7d482f5..75dabd6d 100644 --- a/src/keyboard-x11.c +++ b/src/keyboard-x11.c @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 Robert Tari <robert@tari.in> + * Copyright 2021-2025 Robert Tari <robert@tari.in> * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published @@ -42,6 +42,7 @@ struct _KeyboardPrivate GHashTable *lLayouts; Display *pDisplay; guint nLayout; + guint nLayoutOSK; gint nXkbEventType; XklConfigRec *pConfigRec; GSList *lLayoutRec; @@ -369,7 +370,7 @@ void keyboard_AddSource(Keyboard *pKeyboard) } } -guint keyboard_GetNumLayouts(Keyboard *pKeyboard) +guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK) { guint nLayouts = 0; @@ -385,12 +386,12 @@ guint keyboard_GetNumLayouts(Keyboard *pKeyboard) return nLayouts; } -guint keyboard_GetLayoutIndex (Keyboard *pKeyboard) +guint keyboard_GetLayoutIndex (Keyboard *pKeyboard, gboolean bOSK) { return pKeyboard->pPrivate->nLayout; } -void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription) +void keyboard_GetLayout(Keyboard *pKeyboard, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId) { if (nLayout == -1) { @@ -432,10 +433,17 @@ void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gc *pDescription = g_strdup(pLayout->sDescription); } - g_free(sId); + if (pId != NULL) + { + *pId = sId; + } + else + { + g_free(sId); + } } -void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout) +void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout, gboolean bOSK) { if (isGreeter() == FALSE) { @@ -565,6 +573,16 @@ static void onUserChanged (GDBusConnection *pConnection, const gchar *sSender, c } } +gboolean keyboard_hasHardwareKeyboard (Keyboard *self) +{ + return TRUE; +} + +gboolean keyboard_hasSoftwareKeyboard (Keyboard *self) +{ + return FALSE; +} + static void keyboard_init(Keyboard *self) { self->pPrivate = keyboard_get_instance_private(self); diff --git a/src/keyboard.h b/src/keyboard.h index 39f822cd..206c4bf3 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Robert Tari <robert@tari.in> + * Copyright 2021-2025 Robert Tari <robert@tari.in> * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published @@ -46,10 +46,12 @@ struct _KeyboardClass GType keyboard_get_type(void); Keyboard* keyboard_new(); void keyboard_AddSource(Keyboard *pKeyboard); -guint keyboard_GetNumLayouts(Keyboard *pKeyboard); -guint keyboard_GetLayoutIndex (Keyboard *pKeyboard); -void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription); -void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout); +guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK); +guint keyboard_GetLayoutIndex (Keyboard *pKeyboard, gboolean bOSK); +void keyboard_GetLayout(Keyboard *pKeyboard, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId); +void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout, gboolean bOSK); +gboolean keyboard_hasHardwareKeyboard(Keyboard *pKeyboard); +gboolean keyboard_hasSoftwareKeyboard(Keyboard *pKeyboard); G_END_DECLS diff --git a/src/service.c b/src/service.c index 31f6ca3b..123308c9 100644 --- a/src/service.c +++ b/src/service.c @@ -25,14 +25,19 @@ #define ICON_DEFAULT "input-keyboard" +#define HWKBD FALSE +#define OSK TRUE + static guint m_nSignal = 0; static void *m_pLibHandle = NULL; static Keyboard* (*m_fnKeyboardNew)(); static void (*m_fnKeyboardAddSource)(Keyboard *pKeyboard); -static guint (*m_fnKeyboardGetNumLayouts)(Keyboard *pKeyboard); +static guint (*m_fnKeyboardGetNumLayouts)(Keyboard *pKeyboard, gboolean bOSK); static guint (*m_fnKeyboardGetLayoutIndex)(Keyboard *pKeyboard); -static void (*m_fnKeyboardGetLayout)(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription); -static void (*m_fnKeyboardSetLayout)(Keyboard *pKeyboard, gint nLayout); +static void (*m_fnKeyboardGetLayout)(Keyboard *pKeyboard, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId); +static void (*m_fnKeyboardSetLayout)(Keyboard *pKeyboard, gint nLayout, gboolean bOSK); +static gboolean (*m_fnKeyboardHasHardwareKeyboard)(Keyboard *pKeyboard); +static gboolean (*m_fnKeyboardHasSoftwareKeyboard)(Keyboard *pKeyboard); enum { @@ -77,6 +82,7 @@ struct _IndicatorKeyboardServicePrivate GSimpleAction *pSettingsAction; GSimpleAction *pDisplayAction; GSimpleAction *pLayoutAction; + GSimpleAction *pOSKLayoutAction; GMenu *pLayoutSection; Keyboard *pKeyboard; GSettings *pSettings; @@ -120,8 +126,9 @@ static GVariant* createHeaderState(IndicatorKeyboardService *self, int nProfile) } else { + gboolean bHardwareKeyboard = m_fnKeyboardHasHardwareKeyboard (self->pPrivate->pKeyboard); gchar *sLanguage; - m_fnKeyboardGetLayout(self->pPrivate->pKeyboard, -1, &sLanguage, NULL); + m_fnKeyboardGetLayout(self->pPrivate->pKeyboard, self->pPrivate->bLomiri && !bHardwareKeyboard, -1, &sLanguage, NULL, NULL); gchar *sIcon = g_strconcat("ayatana-indicator-keyboard-", sLanguage, NULL); g_free(sLanguage); @@ -148,20 +155,67 @@ static GVariant* createHeaderState(IndicatorKeyboardService *self, int nProfile) return g_variant_builder_end(&cBuilder); } -static GMenuModel* createLayoutSection(IndicatorKeyboardService *self) +static GMenuModel* createLayoutSection(IndicatorKeyboardService *self, gboolean bOSK) { self->pPrivate->pLayoutSection = g_menu_new(); + gboolean bCreate = TRUE; - guint nLayouts = m_fnKeyboardGetNumLayouts(self->pPrivate->pKeyboard); + if (self->pPrivate->bLomiri) + { + if (!bOSK) + { + gboolean bHardwareKeyboard = m_fnKeyboardHasHardwareKeyboard (self->pPrivate->pKeyboard); + + if (bHardwareKeyboard) + { + g_menu_append (self->pPrivate->pLayoutSection, _("External Keyboard"), NULL); + } + else + { + bCreate = FALSE; + } + } + else if (bOSK) + { + gboolean bSoftwareKeyboard = m_fnKeyboardHasSoftwareKeyboard (self->pPrivate->pKeyboard); + g_menu_append (self->pPrivate->pLayoutSection, _("On-Screen Keyboard"), NULL); + + if (!bSoftwareKeyboard) + { + bCreate = FALSE; + } + } + } + else if (bOSK) + { + bCreate = FALSE; + } + if (!bCreate) + { + return G_MENU_MODEL(self->pPrivate->pLayoutSection); + } + + guint nLayouts = m_fnKeyboardGetNumLayouts(self->pPrivate->pKeyboard, bOSK); for (guint nLayout = 0; nLayout < nLayouts; nLayout++) { gchar *sLanguage; gchar *sDescription; - m_fnKeyboardGetLayout(self->pPrivate->pKeyboard, nLayout, &sLanguage, &sDescription); + m_fnKeyboardGetLayout(self->pPrivate->pKeyboard, bOSK, nLayout, &sLanguage, &sDescription, NULL); GMenuItem *pItem = g_menu_item_new(sDescription, NULL); g_free(sDescription); - g_menu_item_set_action_and_target_value(pItem, "indicator.layout", g_variant_new_byte(nLayout)); + gchar *sAction = NULL; + + if (bOSK) + { + sAction = "indicator.osklayout"; + } + else + { + sAction = "indicator.layout"; + } + + g_menu_item_set_action_and_target_value(pItem, sAction, g_variant_new_byte(nLayout)); g_menu_item_set_attribute_value(pItem, "x-ayatana-layout", g_variant_new_byte(nLayout)); gchar *sIcon = g_strconcat("ayatana-indicator-keyboard-", sLanguage, NULL); g_free(sLanguage); @@ -184,11 +238,12 @@ static GMenuModel* createLayoutSection(IndicatorKeyboardService *self) return G_MENU_MODEL(self->pPrivate->pLayoutSection); } -static GMenuModel* createSettingsSection(IndicatorKeyboardService *self) +static GMenuModel* createSettingsSection(IndicatorKeyboardService *self, gboolean bOSK) { GMenu * pMenu = g_menu_new(); + gboolean bUbuntuTouch = ayatana_common_utils_is_ubuntutouch (); - if (self->pPrivate->bLomiri && (!ayatana_common_utils_is_ubuntutouch())) + if (self->pPrivate->bLomiri && bOSK && !bUbuntuTouch) { GMenuItem *pItem = g_menu_item_new (_("Always show OSK"), "indicator.osk(true)"); g_menu_item_set_attribute (pItem, "x-ayatana-type", "s", "org.ayatana.indicator.switch"); @@ -196,7 +251,33 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self) g_object_unref (pItem); } - g_menu_append(pMenu, _("Keyboard Settings…"), "indicator.settings"); + gchar *sAction = NULL; + + if (self->pPrivate->bLomiri) + { + if (!bOSK) + { + gboolean bHardwareKeyboard = m_fnKeyboardHasHardwareKeyboard (self->pPrivate->pKeyboard); + + if (bHardwareKeyboard) + { + sAction = "indicator.settings"; + } + } + else if (bOSK) + { + sAction = "indicator.osksettings"; + } + } + else if (!bOSK) + { + sAction = "indicator.settings"; + } + + if (sAction) + { + g_menu_append(pMenu, _("Keyboard Settings…"), sAction); + } return G_MENU_MODEL(pMenu); } @@ -204,7 +285,22 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self) static GMenuModel* createDisplaySection (IndicatorKeyboardService *self) { GMenu * pMenu = g_menu_new (); - g_menu_append (pMenu, _("Show Current Layout"), "indicator.display"); + gboolean bDisplay = TRUE; + + if (self->pPrivate->bLomiri) + { + gboolean bHardwareKeyboard = m_fnKeyboardHasHardwareKeyboard (self->pPrivate->pKeyboard); + + if (!bHardwareKeyboard) + { + bDisplay = FALSE; + } + } + + if (bDisplay) + { + g_menu_append (pMenu, _("Show Current Layout"), "indicator.display"); + } return G_MENU_MODEL (pMenu); } @@ -236,9 +332,12 @@ static void rebuildNow(IndicatorKeyboardService *self, guint nSections) if (nSections & SECTION_LAYOUTS) { - rebuildSection(pInfoDesktop->pSubmenu, 0, createLayoutSection(self)); - rebuildSection(pInfoPhone->pSubmenu, 0, createLayoutSection(self)); - rebuildSection(pInfoGreeter->pSubmenu, 0, createLayoutSection(self)); + rebuildSection(pInfoDesktop->pSubmenu, 0, createLayoutSection(self, HWKBD)); + rebuildSection(pInfoDesktop->pSubmenu, 3, createLayoutSection(self, OSK)); + rebuildSection(pInfoPhone->pSubmenu, 0, createLayoutSection(self, HWKBD)); + rebuildSection(pInfoPhone->pSubmenu, 2, createLayoutSection(self, OSK)); + rebuildSection(pInfoGreeter->pSubmenu, 0, createLayoutSection(self, HWKBD)); + rebuildSection(pInfoGreeter->pSubmenu, 1, createLayoutSection(self, OSK)); } if (nSections & SECTION_DISPLAY) @@ -248,8 +347,10 @@ static void rebuildNow(IndicatorKeyboardService *self, guint nSections) if (nSections & SECTION_SETTINGS) { - rebuildSection(pInfoDesktop->pSubmenu, 2, createSettingsSection(self)); - rebuildSection(pInfoPhone->pSubmenu, 2, createSettingsSection(self)); + rebuildSection(pInfoDesktop->pSubmenu, 2, createSettingsSection(self, HWKBD)); + rebuildSection(pInfoDesktop->pSubmenu, 4, createSettingsSection(self, OSK)); + rebuildSection(pInfoPhone->pSubmenu, 1, createSettingsSection(self, HWKBD)); + rebuildSection(pInfoPhone->pSubmenu, 3, createSettingsSection(self, OSK)); } } @@ -267,18 +368,23 @@ static void createMenu(IndicatorKeyboardService *self, int nProfile) // Build the sections if (nProfile == PROFILE_PHONE) { - lSections[nSection++] = createLayoutSection(self); - lSections[nSection++] = createSettingsSection(self); + lSections[nSection++] = createLayoutSection(self, HWKBD); + lSections[nSection++] = createSettingsSection(self, HWKBD); + lSections[nSection++] = createLayoutSection(self, OSK); + lSections[nSection++] = createSettingsSection(self, OSK); } else if (nProfile == PROFILE_DESKTOP) { - lSections[nSection++] = createLayoutSection(self); + lSections[nSection++] = createLayoutSection(self, HWKBD); lSections[nSection++] = createDisplaySection(self); - lSections[nSection++] = createSettingsSection(self); + lSections[nSection++] = createSettingsSection(self, HWKBD); + lSections[nSection++] = createLayoutSection(self, OSK); + lSections[nSection++] = createSettingsSection(self, OSK); } else if (nProfile == PROFILE_GREETER) { - lSections[nSection++] = createLayoutSection(self); + lSections[nSection++] = createLayoutSection(self, HWKBD); + lSections[nSection++] = createLayoutSection(self, OSK); } // Add sections to the submenu @@ -323,7 +429,14 @@ static void onLayoutSelected(GSimpleAction *pAction, GVariant *pVariant, gpointe { IndicatorKeyboardService *self = INDICATOR_KEYBOARD_SERVICE(pData); const guint8 nLayout = g_variant_get_byte(pVariant); - m_fnKeyboardSetLayout(self->pPrivate->pKeyboard, nLayout); + m_fnKeyboardSetLayout(self->pPrivate->pKeyboard, nLayout, HWKBD); +} + +static void onOSKLayoutSelected (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) +{ + IndicatorKeyboardService *self = INDICATOR_KEYBOARD_SERVICE (pData); + const guint8 nLayout = g_variant_get_byte (pVariant); + m_fnKeyboardSetLayout (self->pPrivate->pKeyboard, nLayout, OSK); } static void onSettings(GSimpleAction *pAction, GVariant *pVariant, gpointer pData) @@ -340,22 +453,37 @@ static void onSettings(GSimpleAction *pAction, GVariant *pVariant, gpointer pDat } } +static void onOSKSettings(GSimpleAction *pAction, GVariant *pVariant, gpointer pData) +{ + ayatana_common_utils_open_url ("settings:///system/sw-keyboard-layouts"); +} + static void onDisplay (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) { IndicatorKeyboardService *self = INDICATOR_KEYBOARD_SERVICE (pData); guint nLayout = m_fnKeyboardGetLayoutIndex (self->pPrivate->pKeyboard); gchar *sProgram = NULL; + gchar *sArgs = NULL; + gboolean bMate = ayatana_common_utils_is_mate (); + gboolean bLomiri = ayatana_common_utils_is_lomiri (); - if (ayatana_common_utils_is_mate ()) + if (bMate) { sProgram = "matekbd-keyboard-display"; + sArgs = g_strdup_printf ("-g %i", nLayout + 1); + } + else if (bLomiri) + { + + sProgram = "tecla"; + m_fnKeyboardGetLayout (self->pPrivate->pKeyboard, HWKBD, -1, NULL, NULL, &sArgs); } else { sProgram = "gkbd-keyboard-display"; + sArgs = g_strdup_printf ("-g %i", nLayout + 1); } - gchar *sArgs = g_strdup_printf ("-g %i", nLayout + 1); ayatana_common_utils_execute_command_warn (sProgram, sArgs); g_free (sArgs); } @@ -393,6 +521,14 @@ static void initActions(IndicatorKeyboardService *self) self->pPrivate->pLayoutAction = pAction; g_signal_connect(pAction, "activate", G_CALLBACK(onLayoutSelected), self); + if (self->pPrivate->bLomiri) + { + pAction = g_simple_action_new("osklayout", G_VARIANT_TYPE_BYTE); + g_action_map_add_action(G_ACTION_MAP(self->pPrivate->pActionGroup), G_ACTION(pAction)); + self->pPrivate->pOSKLayoutAction = pAction; + g_signal_connect(pAction, "activate", G_CALLBACK(onOSKLayoutSelected), self); + } + if (self->pPrivate->bLomiri && (!ayatana_common_utils_is_ubuntutouch())) { gboolean bOsk = g_settings_get_boolean (self->pPrivate->pLomiriSettings, "always-show-osk"); @@ -408,6 +544,14 @@ static void initActions(IndicatorKeyboardService *self) self->pPrivate->pSettingsAction = pAction; g_signal_connect(pAction, "activate", G_CALLBACK(onSettings), self); + if (self->pPrivate->bLomiri) + { + pAction = g_simple_action_new ("osksettings", NULL); + g_action_map_add_action(G_ACTION_MAP (self->pPrivate->pActionGroup), G_ACTION (pAction)); + self->pPrivate->pSettingsAction = pAction; + g_signal_connect (pAction, "activate", G_CALLBACK (onOSKSettings), self); + } + pAction = g_simple_action_new ("display", NULL); g_action_map_add_action (G_ACTION_MAP (self->pPrivate->pActionGroup), G_ACTION (pAction)); self->pPrivate->pDisplayAction = pAction; @@ -524,6 +668,7 @@ static void onDispose(GObject *pObject) g_clear_object (&self->pPrivate->pSettingsAction); g_clear_object (&self->pPrivate->pDisplayAction); g_clear_object (&self->pPrivate->pLayoutAction); + g_clear_object (&self->pPrivate->pOSKLayoutAction); for (int nProfile = 0; nProfile < N_PROFILES; ++nProfile) { @@ -579,6 +724,8 @@ static void indicator_keyboard_service_init(IndicatorKeyboardService *self) m_fnKeyboardGetLayoutIndex = dlsym(m_pLibHandle, "keyboard_GetLayoutIndex"); m_fnKeyboardGetLayout = dlsym(m_pLibHandle, "keyboard_GetLayout"); m_fnKeyboardSetLayout = dlsym(m_pLibHandle, "keyboard_SetLayout"); + m_fnKeyboardHasHardwareKeyboard = dlsym(m_pLibHandle, "keyboard_hasHardwareKeyboard"); + m_fnKeyboardHasSoftwareKeyboard = dlsym(m_pLibHandle, "keyboard_hasSoftwareKeyboard"); self->pPrivate = indicator_keyboard_service_get_instance_private(self); self->pPrivate->bLomiri = bLomiri; self->pPrivate->pCancellable = g_cancellable_new(); |
