[Pkg-ayatana-devel] Bug#1109781: unblock: ayatana-indicator-keyboard/24.7.2-5

Mike Gabriel mike.gabriel at das-netzwerkteam.de
Wed Jul 23 18:17:04 BST 2025


Package: release.debian.org
Severity: normal
X-Debbugs-Cc: ayatana-indicator-keyboard at packages.debian.org
Control: affects -1 + src:ayatana-indicator-keyboard
User: release.debian.org at packages.debian.org
Usertags: unblock

Please unblock package ayatana-indicator-keyboard

[ Reason ]
This version contains an additional feature for Lomiri that allows
layout switching for the on-screen keyboard.

For tablet users, the previous ayatana-indicator-keyboard version would
only and always show the hardware keyboard's layouts and settings menu
item. This was quite counter-intuitive for tablet users.

+ayatana-indicator-keyboard (24.7.2-3) unstable; urgency=medium
+
+  * debian/patches:
+    + Add 0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch,
+      0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch,
+      0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch and
+      0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch.
+      Support configuring on-screen keyboard and external hardware keyboard(s)
+      separately via keyboard indicator in Lomiri.
+
+ -- Mike Gabriel <sunweaver at debian.org>  Mon, 21 Jul 2025 15:55:51 +0200

-> this upload contained the first version of the patch series adding
the OSK layout chooser to the keyboard indicator.

+ayatana-indicator-keyboard (24.7.2-4) unstable; urgency=medium
+
+  * debian/control:
+    + Add to B-D: libudev-dev. Fix FTBFS of previous revision.
+
+ -- Mike Gabriel <sunweaver at debian.org>  Tue, 22 Jul 2025 06:24:17 +0200
+

-> this upload fixed a missing B-D (which I failed to add in the
previous upload).

+ayatana-indicator-keyboard (24.7.2-5) unstable; urgency=medium
+
+  * debian/patches:
+    + Update 0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch.
+      Fix regression, external hw layouts not being displayed anymore outside
+      of Lomiri (e.g. in MATE).
+    + Update patches (no-op changes) 0004 - 0007.
+
+ -- Mike Gabriel <sunweaver at debian.org>  Tue, 22 Jul 2025 12:01:42 +0200
+

The last -5 upload fixes a regression in non-Lomiri environments (tested with MATE).

[ Impact ]
Confusing on-screen-keyboard usability / configurability in Lomiri's keyboard indicator.

[ Tests ]
Manual tests on various hardware devices. Esp. a Starlite Tablet with detachable keyboard.

[ Risks ]
For Lomiri users, for other consumers of the keyboard indicator. Only
Lomiri uses Ayatana Indicators by default, all other desktop envs use
them optionally.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
Relevant for Lomiri in Debian.

unblock ayatana-indicator-keyboard/24.7.2-5
-------------- next part --------------
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/changelog ayatana-indicator-keyboard-24.7.2/debian/changelog
--- ayatana-indicator-keyboard-24.7.2/debian/changelog	2025-06-06 16:18:39.000000000 +0200
+++ ayatana-indicator-keyboard-24.7.2/debian/changelog	2025-07-22 12:01:42.000000000 +0200
@@ -1,3 +1,32 @@
+ayatana-indicator-keyboard (24.7.2-5) unstable; urgency=medium
+
+  * debian/patches:
+    + Update 0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch.
+      Fix regression, external hw layouts not being displayed anymore outside
+      of Lomiri (e.g. in MATE).
+    + Update patches (no-op changes) 0004 - 0007.
+
+ -- Mike Gabriel <sunweaver at debian.org>  Tue, 22 Jul 2025 12:01:42 +0200
+
+ayatana-indicator-keyboard (24.7.2-4) unstable; urgency=medium
+
+  * debian/control:
+    + Add to B-D: libudev-dev. Fix FTBFS of previous revision.
+
+ -- Mike Gabriel <sunweaver at debian.org>  Tue, 22 Jul 2025 06:24:17 +0200
+
+ayatana-indicator-keyboard (24.7.2-3) unstable; urgency=medium
+
+  * debian/patches:
+    + Add 0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch,
+      0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch,
+      0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch and
+      0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch.
+      Support configuring on-screen keyboard and external hardware keyboard(s)
+      separately via keyboard indicator in Lomiri.
+
+ -- Mike Gabriel <sunweaver at debian.org>  Mon, 21 Jul 2025 15:55:51 +0200
+
 ayatana-indicator-keyboard (24.7.2-2) unstable; urgency=medium
 
   * debian/patches:
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/control ayatana-indicator-keyboard-24.7.2/debian/control
--- ayatana-indicator-keyboard-24.7.2/debian/control	2025-05-15 09:08:15.000000000 +0200
+++ ayatana-indicator-keyboard-24.7.2/debian/control	2025-07-22 06:23:47.000000000 +0200
@@ -14,6 +14,7 @@
                libxkbcommon-dev (>=1.0.3),
                libxkbregistry-dev (>=1.0.3),
                libaccountsservice-dev,
+               libudev-dev,
 # for packaging
                debhelper-compat (= 13),
                dpkg-dev (>= 1.16.1.1),
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/patches/0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch ayatana-indicator-keyboard-24.7.2/debian/patches/0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch
--- ayatana-indicator-keyboard-24.7.2/debian/patches/0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch	1970-01-01 01:00:00.000000000 +0100
+++ ayatana-indicator-keyboard-24.7.2/debian/patches/0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch	2025-07-22 11:56:36.000000000 +0200
@@ -0,0 +1,899 @@
+From 4de4c6757ad71cad0ee77ffdfde7fb19fb4541a8 Mon Sep 17 00:00:00 2001
+From: Robert Tari <robert at tari.in>
+Date: Tue, 17 Jun 2025 16:08:25 +0200
+Subject: [PATCH 3/7] Separate layout and settings for hardware and on-screen
+ keyboards
+
+Refurbished by Mike Gabriel, avoiding white-space changes, variable renamings and internal code block moves.
+
+Fixes: https://salsa.debian.org/ubports-team/lomiri-system-settings/-/issues/20
+Signed-off-by: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+---
+ CMakeLists.txt        |   3 +-
+ src/keyboard-lomiri.c | 346 +++++++++++++++++++++++++++++++++++++++++-
+ src/keyboard-x11.c    |  16 +-
+ src/keyboard.h        |   8 +-
+ src/service.c         | 189 ++++++++++++++++++++---
+ 5 files changed, 526 insertions(+), 36 deletions(-)
+
+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/src/keyboard-lomiri.c b/src/keyboard-lomiri.c
+index bc6b3f93..d222a06a 100644
+--- a/src/keyboard-lomiri.c
++++ b/src/keyboard-lomiri.c
+@@ -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,
+@@ -35,8 +62,16 @@ struct _KeyboardPrivate
+     GHashTable *lLayouts;
+     guint nLayout;
+     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,9 +204,20 @@ 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)
+@@ -179,14 +225,25 @@ guint keyboard_GetLayoutIndex (Keyboard *pKeyboard)
+     return pKeyboard->pPrivate->nLayout;
+ }
+ 
+-void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId)
++void keyboard_GetLayout(Keyboard *pKeyboard, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId)
+ {
+     if (nLayout == -1)
+     {
+         nLayout = pKeyboard->pPrivate->nLayout;
+     }
+ 
+-    gchar *sLayout = g_slist_nth_data (pKeyboard->pPrivate->lLayoutRec, nLayout);
++    GSList *lLayoutRec = NULL;
++
++    if (bOSK)
++    {
++        lLayoutRec = pKeyboard->pPrivate->lLayoutRecOSK;
++    }
++    else
++    {
++        lLayoutRec = pKeyboard->pPrivate->lLayoutRec;
++    }
++
++    gchar *sLayout = g_slist_nth_data (lLayoutRec, nLayout);
+     const Layout *pLayout;
+     g_hash_table_lookup_extended(pKeyboard->pPrivate->lLayouts, sLayout, NULL, (gpointer*)&pLayout);
+ 
+@@ -206,7 +263,7 @@ void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gc
+     }
+ }
+ 
+-void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout)
++void keyboard_SetLayoutHardware(Keyboard *pKeyboard, gint nLayout)
+ {
+     if (isGreeter() == FALSE)
+     {
+@@ -298,11 +355,62 @@ 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 *sLayout = NULL;
++
++        while (LOMIRI_TO_ISO[nId][0] != NULL)
++        {
++            gboolean bEqual = g_str_equal (LOMIRI_TO_ISO[nId][1], sId);
++
++            if (bEqual)
++            {
++                sLayout = LOMIRI_TO_ISO[nId][0];
++
++                break;
++            }
++
++            nId++;
++        }
++
++        if (!sLayout)
++        {
++            sLayout = sId;
++        }
++
++        g_settings_set_string (pKeyboard->pPrivate->pMaliitSettings, "active-language", sLayout);
++    }
++    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)
+     {
+@@ -314,11 +422,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);
+ }
+ 
+@@ -376,10 +504,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
+@@ -427,6 +695,25 @@ static void keyboard_init(Keyboard *self)
+ 
+     rxkb_context_unref(pContext);
+ 
++    // 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;
+@@ -497,4 +784,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 27dfb97c..89e78517 100644
+--- a/src/keyboard-x11.c
++++ b/src/keyboard-x11.c
+@@ -369,7 +369,7 @@ void keyboard_AddSource(Keyboard *pKeyboard)
+     }
+ }
+ 
+-guint keyboard_GetNumLayouts(Keyboard *pKeyboard)
++guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK)
+ {
+     guint nLayouts = 0;
+ 
+@@ -390,7 +390,7 @@ guint keyboard_GetLayoutIndex (Keyboard *pKeyboard)
+     return pKeyboard->pPrivate->nLayout;
+ }
+ 
+-void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId)
++void keyboard_GetLayout(Keyboard *pKeyboard, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId)
+ {
+     if (nLayout == -1)
+     {
+@@ -442,7 +442,7 @@ void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gc
+     }
+ }
+ 
+-void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout)
++void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout, gboolean bOSK)
+ {
+     if (isGreeter() == FALSE)
+     {
+@@ -572,6 +572,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 49c21056..fd30cf6d 100644
+--- a/src/keyboard.h
++++ b/src/keyboard.h
+@@ -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_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK);
+ guint keyboard_GetLayoutIndex (Keyboard *pKeyboard);
+-void keyboard_GetLayout(Keyboard *pKeyboard, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId);
+-void keyboard_SetLayout(Keyboard *pKeyboard, gint nLayout);
++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 f4b086cc..ee37ef96 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, gchar **pId);
+-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, 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,64 @@ 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 = FALSE;
++
++    if (self->pPrivate->bLomiri)
++    {
++        gboolean bHardwareKeyboard = m_fnKeyboardHasHardwareKeyboard (self->pPrivate->pKeyboard);
++
++        if (!bOSK)
++        {
++            if (bHardwareKeyboard)
++            {
++                g_menu_append (self->pPrivate->pLayoutSection, _("External Keyboard"), NULL);
++                bCreate = TRUE;
++            }
++        }
++        else if (bOSK)
++        {
++            gboolean bSoftwareKeyboard = m_fnKeyboardHasSoftwareKeyboard (self->pPrivate->pKeyboard);
+ 
+-    guint nLayouts = m_fnKeyboardGetNumLayouts(self->pPrivate->pKeyboard);
++            if (bSoftwareKeyboard || !bHardwareKeyboard)
++            {
++                g_menu_append (self->pPrivate->pLayoutSection, _("On-Screen Keyboard"), NULL);
++                bCreate = TRUE;
++            }
++        }
++    }
++    else if (!bOSK) {
++        bCreate = TRUE;
++    }
++
++    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, NULL);
++        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 +235,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 +248,38 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self)
+         g_object_unref (pItem);
+     }
+ 
+-    g_menu_append(pMenu, _("Keyboard Settings?"), "indicator.settings");
++    gchar *sAction = NULL;
++
++    if (self->pPrivate->bLomiri)
++    {
++        gboolean bHardwareKeyboard = m_fnKeyboardHasHardwareKeyboard (self->pPrivate->pKeyboard);
++
++        if (!bOSK)
++        {
++            if (bHardwareKeyboard)
++            {
++                sAction = "indicator.settings";
++            }
++        }
++        else if (bOSK)
++        {
++            gboolean bSoftwareKeyboard = m_fnKeyboardHasSoftwareKeyboard (self->pPrivate->pKeyboard);
++
++            if (bSoftwareKeyboard || !bHardwareKeyboard)
++            {
++                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 +287,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 +334,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 +349,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 +370,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
+@@ -317,13 +425,21 @@ static void onConfigChanged(Keyboard *pKeyboard, gpointer pData)
+ {
+     IndicatorKeyboardService *self = INDICATOR_KEYBOARD_SERVICE(pData);
+     rebuildNow(self, SECTION_LAYOUTS);
++    rebuildNow(self, SECTION_SETTINGS);
+ }
+ 
+ static void onLayoutSelected(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);
++    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,6 +456,11 @@ 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);
+@@ -358,7 +479,7 @@ static void onDisplay (GSimpleAction *pAction, GVariant *pVariant, gpointer pDat
+     {
+ 
+         sProgram = "tecla";
+-        m_fnKeyboardGetLayout (self->pPrivate->pKeyboard, -1, NULL, NULL, &sArgs);
++        m_fnKeyboardGetLayout (self->pPrivate->pKeyboard, HWKBD, -1, NULL, NULL, &sArgs);
+     }
+     else
+     {
+@@ -403,6 +524,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");
+@@ -418,6 +547,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;
+@@ -534,6 +671,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)
+     {
+@@ -556,6 +694,7 @@ static void onSettingsChanged(GSettings *pSettings, gchar *sKey, gpointer pData)
+ {
+     IndicatorKeyboardService *self = INDICATOR_KEYBOARD_SERVICE(pData);
+     rebuildNow(self, SECTION_HEADER);
++    rebuildNow(self, SECTION_SETTINGS);
+ }
+ 
+ static void indicator_keyboard_service_init(IndicatorKeyboardService *self)
+@@ -589,6 +728,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();
+-- 
+2.47.2
+
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/patches/0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch ayatana-indicator-keyboard-24.7.2/debian/patches/0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch
--- ayatana-indicator-keyboard-24.7.2/debian/patches/0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch	1970-01-01 01:00:00.000000000 +0100
+++ ayatana-indicator-keyboard-24.7.2/debian/patches/0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch	2025-07-22 11:56:36.000000000 +0200
@@ -0,0 +1,115 @@
+From b5cdd12b186f27cee8cfdfb9ff84c15ca8913582 Mon Sep 17 00:00:00 2001
+From: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+Date: Sun, 22 Jun 2025 21:42:43 +0200
+Subject: [PATCH 4/7] src/keyboard*: Remember nLayout and nLayoutOSK
+ separately.
+
+Signed-off-by: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+---
+ src/keyboard-lomiri.c | 26 ++++++++++++++++++++------
+ src/keyboard-x11.c    |  3 ++-
+ src/keyboard.h        |  2 +-
+ 3 files changed, 23 insertions(+), 8 deletions(-)
+
+diff --git a/src/keyboard-lomiri.c b/src/keyboard-lomiri.c
+index d222a06a..ae2f7961 100644
+--- a/src/keyboard-lomiri.c
++++ b/src/keyboard-lomiri.c
+@@ -61,6 +61,7 @@ struct _KeyboardPrivate
+ {
+     GHashTable *lLayouts;
+     guint nLayout;
++    guint nLayoutOSK;
+     GSList *lLayoutRec;
+     GSList *lLayoutRecOSK;
+     GSList *lUsers;
+@@ -220,26 +221,37 @@ guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK)
+     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, gboolean bOSK, gint nLayout, gchar **pLanguage, gchar **pDescription, gchar **pId)
+ {
+-    if (nLayout == -1)
+-    {
+-        nLayout = pKeyboard->pPrivate->nLayout;
+-    }
+ 
+     GSList *lLayoutRec = NULL;
+ 
+     if (bOSK)
+     {
++        if (nLayout == -1)
++        {
++            nLayout = pKeyboard->pPrivate->nLayoutOSK;
++        }
+         lLayoutRec = pKeyboard->pPrivate->lLayoutRecOSK;
+     }
+     else
+     {
++        if (nLayout == -1)
++        {
++            nLayout = pKeyboard->pPrivate->nLayout;
++        }
+         lLayoutRec = pKeyboard->pPrivate->lLayoutRec;
+     }
+ 
+@@ -695,6 +707,8 @@ static void keyboard_init(Keyboard *self)
+ 
+     rxkb_context_unref(pContext);
+ 
++    self->pPrivate->nLayoutOSK = 0;
++
+     // Lomiri-specific layouts
+     const gchar *LAYOUTS[][3] =
+     {
+diff --git a/src/keyboard-x11.c b/src/keyboard-x11.c
+index 89e78517..75dabd6d 100644
+--- a/src/keyboard-x11.c
++++ b/src/keyboard-x11.c
+@@ -42,6 +42,7 @@ struct _KeyboardPrivate
+     GHashTable *lLayouts;
+     Display *pDisplay;
+     guint nLayout;
++    guint nLayoutOSK;
+     gint nXkbEventType;
+     XklConfigRec *pConfigRec;
+     GSList *lLayoutRec;
+@@ -385,7 +386,7 @@ guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK)
+     return nLayouts;
+ }
+ 
+-guint keyboard_GetLayoutIndex (Keyboard *pKeyboard)
++guint keyboard_GetLayoutIndex (Keyboard *pKeyboard, gboolean bOSK)
+ {
+     return pKeyboard->pPrivate->nLayout;
+ }
+diff --git a/src/keyboard.h b/src/keyboard.h
+index fd30cf6d..206c4bf3 100644
+--- a/src/keyboard.h
++++ b/src/keyboard.h
+@@ -47,7 +47,7 @@ GType keyboard_get_type(void);
+ Keyboard* keyboard_new();
+ void keyboard_AddSource(Keyboard *pKeyboard);
+ guint keyboard_GetNumLayouts(Keyboard *pKeyboard, gboolean bOSK);
+-guint keyboard_GetLayoutIndex (Keyboard *pKeyboard);
++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);
+-- 
+2.47.2
+
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/patches/0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch ayatana-indicator-keyboard-24.7.2/debian/patches/0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch
--- ayatana-indicator-keyboard-24.7.2/debian/patches/0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch	1970-01-01 01:00:00.000000000 +0100
+++ ayatana-indicator-keyboard-24.7.2/debian/patches/0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch	2025-07-22 11:56:36.000000000 +0200
@@ -0,0 +1,94 @@
+From cad4f9b0712b7816624636d56feebcfebd3d6025 Mon Sep 17 00:00:00 2001
+From: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+Date: Mon, 23 Jun 2025 09:59:14 +0200
+Subject: [PATCH 5/7] src/keyboard-lomiri.c: For OSK layouts, update
+ 'enabled-languages' gsettings and move the newly selected 'active-language'
+ to the top.
+
+Signed-off-by: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+---
+ src/keyboard-lomiri.c | 51 ++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 46 insertions(+), 5 deletions(-)
+
+diff --git a/src/keyboard-lomiri.c b/src/keyboard-lomiri.c
+index ae2f7961..176d576b 100644
+--- a/src/keyboard-lomiri.c
++++ b/src/keyboard-lomiri.c
+@@ -373,7 +373,7 @@ void keyboard_SetLayoutSoftware(Keyboard *pKeyboard, gint nLayout)
+     {
+         gchar *sId = g_slist_nth_data (pKeyboard->pPrivate->lLayoutRecOSK, nLayout);
+         guint nId = 0;
+-        gchar *sLayout = NULL;
++        gchar *sLayoutOSK = NULL;
+ 
+         while (LOMIRI_TO_ISO[nId][0] != NULL)
+         {
+@@ -381,7 +381,7 @@ void keyboard_SetLayoutSoftware(Keyboard *pKeyboard, gint nLayout)
+ 
+             if (bEqual)
+             {
+-                sLayout = LOMIRI_TO_ISO[nId][0];
++                sLayoutOSK = LOMIRI_TO_ISO[nId][0];
+ 
+                 break;
+             }
+@@ -389,12 +389,53 @@ void keyboard_SetLayoutSoftware(Keyboard *pKeyboard, gint nLayout)
+             nId++;
+         }
+ 
+-        if (!sLayout)
++        if (!sLayoutOSK)
+         {
+-            sLayout = sId;
++            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", sLayout);
++        g_settings_set_string (pKeyboard->pPrivate->pMaliitSettings, "active-language", sLayoutOSK);
++        g_settings_set_value (pKeyboard->pPrivate->pMaliitSettings, "enabled-languages", pEnabledLayoutsOSK);
+     }
+     else
+     {
+-- 
+2.47.2
+
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/patches/0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch ayatana-indicator-keyboard-24.7.2/debian/patches/0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch
--- ayatana-indicator-keyboard-24.7.2/debian/patches/0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch	1970-01-01 01:00:00.000000000 +0100
+++ ayatana-indicator-keyboard-24.7.2/debian/patches/0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch	2025-07-22 11:56:36.000000000 +0200
@@ -0,0 +1,122 @@
+From 891c2ebcb8f1b001e8bd366d8fc6df70ad4e463a Mon Sep 17 00:00:00 2001
+From: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+Date: Mon, 21 Jul 2025 08:45:00 +0200
+Subject: [PATCH 6/7] src/service.c: Move 'Show Current Layout' menuitem closer
+ HWK settings (i.e. drop one menu separator).
+
+Signed-off-by: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+---
+ src/service.c | 45 +++++++++++----------------------------------
+ 1 file changed, 11 insertions(+), 34 deletions(-)
+
+diff --git a/src/service.c b/src/service.c
+index ee37ef96..54d2327f 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -43,8 +43,7 @@ enum
+ {
+     SECTION_HEADER = (1 << 0),
+     SECTION_LAYOUTS = (1 << 1),
+-    SECTION_DISPLAY = (1 << 2),
+-    SECTION_SETTINGS = (1 << 3)
++    SECTION_SETTINGS = (1 << 2)
+ };
+ 
+ enum
+@@ -239,6 +238,7 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self, gboolea
+ {
+     GMenu * pMenu = g_menu_new();
+     gboolean bUbuntuTouch = ayatana_common_utils_is_ubuntutouch ();
++    gboolean bDisplay = FALSE;
+ 
+     if (self->pPrivate->bLomiri && bOSK && !bUbuntuTouch)
+     {
+@@ -259,6 +259,7 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self, gboolea
+             if (bHardwareKeyboard)
+             {
+                 sAction = "indicator.settings";
++                bDisplay = TRUE;
+             }
+         }
+         else if (bOSK)
+@@ -274,8 +275,13 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self, gboolea
+     else if (!bOSK)
+     {
+         sAction = "indicator.settings";
++        bDisplay = TRUE;
+     }
+ 
++    if (bDisplay)
++    {
++        g_menu_append (pMenu, _("Show Current Layout"), "indicator.display");
++    }
+     if (sAction)
+     {
+         g_menu_append(pMenu, _("Keyboard Settings?"), sAction);
+@@ -284,29 +290,6 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self, gboolea
+     return G_MENU_MODEL(pMenu);
+ }
+ 
+-static GMenuModel* createDisplaySection (IndicatorKeyboardService *self)
+-{
+-    GMenu * pMenu = g_menu_new ();
+-    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);
+-}
+-
+ static void rebuildSection(GMenu *pMenu, int nPos, GMenuModel *pModel)
+ {
+     g_menu_remove(pMenu, nPos);
+@@ -335,22 +318,17 @@ static void rebuildNow(IndicatorKeyboardService *self, guint nSections)
+     if (nSections & SECTION_LAYOUTS)
+     {
+         rebuildSection(pInfoDesktop->pSubmenu, 0, createLayoutSection(self, HWKBD));
+-        rebuildSection(pInfoDesktop->pSubmenu, 3, createLayoutSection(self, OSK));
++        rebuildSection(pInfoDesktop->pSubmenu, 2, 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)
+-    {
+-        rebuildSection (pInfoDesktop->pSubmenu, 1, createDisplaySection (self));
+-    }
+-
+     if (nSections & SECTION_SETTINGS)
+     {
+-        rebuildSection(pInfoDesktop->pSubmenu, 2, createSettingsSection(self, HWKBD));
+-        rebuildSection(pInfoDesktop->pSubmenu, 4, createSettingsSection(self, OSK));
++        rebuildSection(pInfoDesktop->pSubmenu, 1, createSettingsSection(self, HWKBD));
++        rebuildSection(pInfoDesktop->pSubmenu, 3, createSettingsSection(self, OSK));
+         rebuildSection(pInfoPhone->pSubmenu, 1, createSettingsSection(self, HWKBD));
+         rebuildSection(pInfoPhone->pSubmenu, 3, createSettingsSection(self, OSK));
+     }
+@@ -378,7 +356,6 @@ static void createMenu(IndicatorKeyboardService *self, int nProfile)
+     else if (nProfile == PROFILE_DESKTOP)
+     {
+         lSections[nSection++] = createLayoutSection(self, HWKBD);
+-        lSections[nSection++] = createDisplaySection(self);
+         lSections[nSection++] = createSettingsSection(self, HWKBD);
+         lSections[nSection++] = createLayoutSection(self, OSK);
+         lSections[nSection++] = createSettingsSection(self, OSK);
+-- 
+2.47.2
+
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/patches/0007_src-service.c-Don-t-show-OSK-settings-when-on-Ubuntu.patch ayatana-indicator-keyboard-24.7.2/debian/patches/0007_src-service.c-Don-t-show-OSK-settings-when-on-Ubuntu.patch
--- ayatana-indicator-keyboard-24.7.2/debian/patches/0007_src-service.c-Don-t-show-OSK-settings-when-on-Ubuntu.patch	1970-01-01 01:00:00.000000000 +0100
+++ ayatana-indicator-keyboard-24.7.2/debian/patches/0007_src-service.c-Don-t-show-OSK-settings-when-on-Ubuntu.patch	2025-07-22 11:56:36.000000000 +0200
@@ -0,0 +1,44 @@
+From e27ff542e907a6c3e00236f161818fce0ac6b77b Mon Sep 17 00:00:00 2001
+From: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+Date: Mon, 21 Jul 2025 14:13:36 +0200
+Subject: [PATCH 7/7] src/service.c: Don't show OSK settings when on Ubuntu
+ Touch.
+
+Signed-off-by: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+---
+ src/service.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/service.c b/src/service.c
+index 54d2327f..7b205327 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -157,6 +157,7 @@ static GVariant* createHeaderState(IndicatorKeyboardService *self, int nProfile)
+ static GMenuModel* createLayoutSection(IndicatorKeyboardService *self, gboolean bOSK)
+ {
+     self->pPrivate->pLayoutSection = g_menu_new();
++    gboolean bUbuntuTouch = ayatana_common_utils_is_ubuntutouch ();
+     gboolean bCreate = FALSE;
+ 
+     if (self->pPrivate->bLomiri)
+@@ -171,7 +172,7 @@ static GMenuModel* createLayoutSection(IndicatorKeyboardService *self, gboolean
+                 bCreate = TRUE;
+             }
+         }
+-        else if (bOSK)
++        else if (bOSK && !bUbuntuTouch)
+         {
+             gboolean bSoftwareKeyboard = m_fnKeyboardHasSoftwareKeyboard (self->pPrivate->pKeyboard);
+ 
+@@ -262,7 +263,7 @@ static GMenuModel* createSettingsSection(IndicatorKeyboardService *self, gboolea
+                 bDisplay = TRUE;
+             }
+         }
+-        else if (bOSK)
++        else if (bOSK && !bUbuntuTouch)
+         {
+             gboolean bSoftwareKeyboard = m_fnKeyboardHasSoftwareKeyboard (self->pPrivate->pKeyboard);
+ 
+-- 
+2.47.2
+
diff -Nru ayatana-indicator-keyboard-24.7.2/debian/patches/series ayatana-indicator-keyboard-24.7.2/debian/patches/series
--- ayatana-indicator-keyboard-24.7.2/debian/patches/series	2025-05-15 08:59:14.000000000 +0200
+++ ayatana-indicator-keyboard-24.7.2/debian/patches/series	2025-07-21 15:55:09.000000000 +0200
@@ -1,3 +1,8 @@
 0001-Try-to-place-the-indicator-in-the-leftmost-position-.patch
 2001_use-keyboard-icon.patch
 0002-Fix-showing-current-layout-on-Lomiri.patch
+0003_Separate-layout-and-settings-for-hardware-and-on-scr.patch
+0004_src-keyboard-Remember-nLayout-and-nLayoutOSK-separat.patch
+0005_src-keyboard-lomiri.c-For-OSK-layouts-update-enabled.patch
+0006_src-service.c-Move-Show-Current-Layout-menuitem-clos.patch
+0007_src-service.c-Don-t-show-OSK-settings-when-on-Ubuntu.patch


More information about the Pkg-ayatana-devel mailing list