[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1109781: marked as done (unblock: ayatana-indicator-keyboard/24.7.2-5)



Your message dated Wed, 23 Jul 2025 19:19:54 +0000
with message-id <E1uef0M-00CgnD-39@respighi.debian.org>
and subject line unblock ayatana-indicator-keyboard
has caused the Debian Bug report #1109781,
regarding unblock: ayatana-indicator-keyboard/24.7.2-5
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1109781: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109781
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: ayatana-indicator-keyboard@packages.debian.org
Control: affects -1 + src:ayatana-indicator-keyboard
User: release.debian.org@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@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@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@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
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@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@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@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@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@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@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@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@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@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@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@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@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@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

--- End Message ---
--- Begin Message ---
Unblocked ayatana-indicator-keyboard.

--- End Message ---

Reply to: