mutter/remote-desktop-keymap.patch
2026-05-20 00:07:03 +02:00

7646 lines
306 KiB
Diff

From 8e6cb6aec87192acf821dac8a31fc4261a82ce0f Mon Sep 17 00:00:00 2001
From: Serhii Tereshchenko <serg.partizan@gmail.com>
Date: Sat, 27 Sep 2025 15:09:29 +0300
Subject: [PATCH 01/32] test: Add test-case for Keyboard Layout Change using
Shift+Caps
Refs #4346
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4707>
(cherry picked from commit 9ad80a4aebe4cfba437b44facd2d072ec3507791)
---
src/tests/keyboard-map-tests.c | 81 ++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index 9b220f81d1..6a547f8cbc 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -186,6 +186,78 @@ meta_test_native_keyboard_map_set_async (void)
g_signal_handler_disconnect (keymap, keymap_state_changed_handler_id);
}
+static void
+meta_test_native_keyboard_map_change_layout (void)
+{
+ MetaBackend *backend = meta_context_get_backend (test_context);
+ ClutterSeat *seat = meta_backend_get_default_seat (backend);
+
+ g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL;
+ struct xkb_keymap *xkb_keymap = meta_backend_get_keymap (backend);
+ struct xkb_keymap *new_xkb_keymap;
+ gboolean done = FALSE;
+
+ virtual_keyboard = clutter_seat_create_virtual_device (seat,
+ CLUTTER_KEYBOARD_DEVICE);
+
+ xkb_keymap_ref (xkb_keymap);
+
+ meta_backend_set_keymap_async (backend,
+ "us,ua",
+ NULL,
+ "grp:caps_select",
+ NULL, NULL,
+ set_keymap_cb, &done);
+
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ new_xkb_keymap = meta_backend_get_keymap (backend);
+ g_assert_true (new_xkb_keymap != xkb_keymap);
+ g_assert_cmpuint (xkb_keymap_num_layouts (new_xkb_keymap), ==, 2);
+ g_assert_cmpstr (xkb_keymap_layout_get_name (new_xkb_keymap, 0),
+ ==,
+ "English (US)");
+ g_assert_cmpstr (xkb_keymap_layout_get_name (new_xkb_keymap, 1),
+ ==,
+ "Ukrainian");
+
+ xkb_keymap_unref (xkb_keymap);
+
+ /* Test layout switching with Caps Lock */
+ /* First verify we start with layout 0 (English US) */
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
+
+ /* Press Shift key */
+ clutter_virtual_input_device_notify_key (virtual_keyboard,
+ g_get_monotonic_time (),
+ KEY_LEFTSHIFT,
+ CLUTTER_KEY_STATE_PRESSED);
+
+ /* Press Caps Lock while Shift is held (Shift+Caps Lock) */
+ clutter_virtual_input_device_notify_key (virtual_keyboard,
+ g_get_monotonic_time (),
+ KEY_CAPSLOCK,
+ CLUTTER_KEY_STATE_PRESSED);
+
+ /* Release Caps Lock */
+ clutter_virtual_input_device_notify_key (virtual_keyboard,
+ g_get_monotonic_time (),
+ KEY_CAPSLOCK,
+ CLUTTER_KEY_STATE_RELEASED);
+
+ /* Release Shift key */
+ clutter_virtual_input_device_notify_key (virtual_keyboard,
+ g_get_monotonic_time (),
+ KEY_LEFTSHIFT,
+ CLUTTER_KEY_STATE_RELEASED);
+ meta_flush_input (test_context);
+ meta_wait_for_update (test_context);
+
+ /* Verify that layout switched to Ukrainian (layout 1) */
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 1);
+}
+
static void
set_keymap_layout_group_cb (GObject *source_object,
GAsyncResult *result,
@@ -218,6 +290,13 @@ meta_test_native_keyboard_map_set_layout_index (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
+ done = FALSE;
+ meta_backend_set_keymap_layout_group_async (backend, 0, NULL,
+ set_keymap_layout_group_cb,
+ &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
keymap = xkb_keymap_ref (meta_backend_get_keymap (backend));
g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
@@ -353,6 +432,8 @@ init_tests (void)
{
g_test_add_func ("/backends/native/keyboard-map/set-async",
meta_test_native_keyboard_map_set_async);
+ g_test_add_func ("/backends/native/keyboard-map/change-layout",
+ meta_test_native_keyboard_map_change_layout);
g_test_add_func ("/backends/native/keyboard-map/set-layout-index",
meta_test_native_keyboard_map_set_layout_index);
g_test_add_func ("/backends/native/keyboard-map/modifiers",
--
2.54.0
From d5f19cd112a590206b18dca94fb9aa22381beca8 Mon Sep 17 00:00:00 2001
From: Sebastian Keller <skeller@gnome.org>
Date: Thu, 22 Jan 2026 14:39:52 +0100
Subject: [PATCH 02/32] keymap/native: Use effective instead of locked layout
group
The locked layout group does not take depressed/latched keys into
consideration, resulting in the layout group not being switched when
using grp:caps_switch and holding caps lock while typing.
Fixes: aeac0f33c2 ("keymap/native: Plumb all modifier state")
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/4528
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4858>
(cherry picked from commit f015c1059ff29adc95383aa725afbe50580df020)
---
clutter/clutter/clutter-keymap-private.h | 2 +-
clutter/clutter/clutter-keymap.c | 10 +++++-----
src/backends/native/meta-keymap-native.c | 8 ++++----
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/clutter/clutter/clutter-keymap-private.h b/clutter/clutter/clutter-keymap-private.h
index fbba11980a..047425c05e 100644
--- a/clutter/clutter/clutter-keymap-private.h
+++ b/clutter/clutter/clutter-keymap-private.h
@@ -24,7 +24,7 @@ CLUTTER_EXPORT
void clutter_keymap_update_state (ClutterKeymap *keymap,
gboolean caps_lock_state,
gboolean num_lock_state,
- xkb_layout_index_t locked_layout_group,
+ xkb_layout_index_t effective_layout_group,
xkb_mod_mask_t depressed_mods,
xkb_mod_mask_t latched_mods,
xkb_mod_mask_t locked_mods);
diff --git a/clutter/clutter/clutter-keymap.c b/clutter/clutter/clutter-keymap.c
index 00bef2933e..8721990f74 100644
--- a/clutter/clutter/clutter-keymap.c
+++ b/clutter/clutter/clutter-keymap.c
@@ -43,7 +43,7 @@ typedef struct _ClutterKeymapPrivate
xkb_mod_mask_t latched_mods;
xkb_mod_mask_t locked_mods;
- xkb_layout_index_t locked_layout_group;
+ xkb_layout_index_t effective_layout_group;
} ClutterKeymapPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterKeymap, clutter_keymap,
@@ -163,7 +163,7 @@ void
clutter_keymap_update_state (ClutterKeymap *keymap,
gboolean caps_lock_state,
gboolean num_lock_state,
- xkb_layout_index_t locked_layout_group,
+ xkb_layout_index_t effective_layout_group,
xkb_mod_mask_t depressed_mods,
xkb_mod_mask_t latched_mods,
xkb_mod_mask_t locked_mods)
@@ -172,13 +172,13 @@ clutter_keymap_update_state (ClutterKeymap *keymap,
if (priv->caps_lock_state == caps_lock_state &&
priv->num_lock_state == num_lock_state &&
- priv->locked_layout_group == locked_layout_group &&
+ priv->effective_layout_group == effective_layout_group &&
priv->depressed_mods == depressed_mods &&
priv->latched_mods == latched_mods &&
priv->locked_mods == locked_mods)
return;
- priv->locked_layout_group = locked_layout_group;
+ priv->effective_layout_group = effective_layout_group;
priv->depressed_mods = depressed_mods;
priv->latched_mods = latched_mods;
priv->locked_mods = locked_mods;
@@ -222,5 +222,5 @@ clutter_keymap_get_layout_index (ClutterKeymap *keymap)
{
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
- return priv->locked_layout_group;
+ return priv->effective_layout_group;
}
diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c
index faa4439f57..8d1d804c12 100644
--- a/src/backends/native/meta-keymap-native.c
+++ b/src/backends/native/meta-keymap-native.c
@@ -112,7 +112,7 @@ typedef struct
xkb_mod_mask_t latched_mods;
xkb_mod_mask_t locked_mods;
- xkb_layout_index_t locked_layout_group;
+ xkb_layout_index_t effective_layout_group;
} UpdateLockedModifierStateData;
static gboolean
@@ -135,7 +135,7 @@ update_state_in_main (gpointer user_data)
clutter_keymap_update_state (CLUTTER_KEYMAP (keymap_native),
caps_lock_state,
num_lock_state,
- data->locked_layout_group,
+ data->effective_layout_group,
data->depressed_mods,
data->latched_mods,
data->locked_mods);
@@ -160,8 +160,8 @@ meta_keymap_native_update_in_impl (MetaKeymapNative *keymap_native,
data->locked_mods =
xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED);
- data->locked_layout_group =
- xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_LOCKED);
+ data->effective_layout_group =
+ xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE);
meta_seat_impl_queue_main_thread_idle (seat_impl,
update_state_in_main,
--
2.54.0
From 3b317ede1d9ecbc1c0db490577d1014edf07d193 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 23 Sep 2025 12:02:15 +0200
Subject: [PATCH 03/32] build: Fix a file sort order issue
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit ece0c71ca17260f79907de86299343bc442d12a8)
---
src/meta/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/meta/meson.build b/src/meta/meson.build
index f34ace7439..601b020044 100644
--- a/src/meta/meson.build
+++ b/src/meta/meson.build
@@ -24,8 +24,8 @@ mutter_public_headers = [
'meta-external-constraint.h',
'meta-idle-monitor.h',
'meta-inhibit-shortcuts-dialog.h',
- 'meta-launch-context.h',
'meta-later.h',
+ 'meta-launch-context.h',
'meta-logical-monitor.h',
'meta-monitor.h',
'meta-monitor-manager.h',
--
2.54.0
From d2c3ab0a4a89c33ea9115f50df6746b6c1ec1b16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Mon, 15 Dec 2025 21:39:18 +0100
Subject: [PATCH 04/32] tests/keyboard-map-tests: Don't leak xkb_keymap
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit c4f7155c900a414a9c45b4d2441c383c82b906b7)
---
src/tests/keyboard-map-tests.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index 6a547f8cbc..bca99da74d 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -297,7 +297,7 @@ meta_test_native_keyboard_map_set_layout_index (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- keymap = xkb_keymap_ref (meta_backend_get_keymap (backend));
+ keymap = meta_backend_get_keymap (backend);
g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
==,
--
2.54.0
From c13eb4351bf2d102f673cb8258233806606de3c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 23 Sep 2025 12:02:54 +0200
Subject: [PATCH 05/32] meta/backend: Fix include order
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 13f59a7765f8e954d94450d61127c2f029542907)
---
src/meta/meta-backend.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h
index 9939f1ae1b..5511acbeec 100644
--- a/src/meta/meta-backend.h
+++ b/src/meta/meta-backend.h
@@ -27,8 +27,8 @@
#include "clutter/clutter.h"
#include "meta/meta-dnd.h"
#include "meta/meta-idle-monitor.h"
-#include "meta/meta-monitor-manager.h"
#include "meta/meta-logical-monitor.h"
+#include "meta/meta-monitor-manager.h"
#include "meta/meta-orientation-manager.h"
#include "meta/meta-remote-access-controller.h"
--
2.54.0
From 7276f386325234493429eccb49e3e6d3b56ac6ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 23 Sep 2025 12:00:04 +0200
Subject: [PATCH 06/32] backend: Set keymap using new MetaKeymapDescription
type
This allows moving some logic to a type that centralizes handling of
describing a keyboard map. It also allows attaching more metadata to the
keymap which will be useful in the future.
The MetaKeymapDescription type is a immutable description of a XKB keyboard
map. Switching related state, i.e. layout index, is done externally to
it.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 0ddaddd628d34a6a371340ff9c5c3994f356a749)
---
src/backends/meta-backend-private.h | 9 +-
src/backends/meta-backend.c | 18 ++--
.../meta-keymap-description-private.h | 27 +++++
src/backends/meta-keymap-description.c | 101 ++++++++++++++++++
src/backends/native/meta-backend-native.c | 11 +-
src/backends/native/meta-seat-native.c | 55 +++++-----
src/backends/native/meta-seat-native.h | 13 +--
src/compositor/plugins/default.c | 11 +-
src/meson.build | 2 +
src/meta/meson.build | 1 +
src/meta/meta-backend.h | 14 ++-
src/meta/meta-keymap-description.h | 44 ++++++++
src/tests/keyboard-map-tests.c | 41 ++++---
src/tests/remote-desktop-tests.c | 7 +-
14 files changed, 267 insertions(+), 87 deletions(-)
create mode 100644 src/backends/meta-keymap-description-private.h
create mode 100644 src/backends/meta-keymap-description.c
create mode 100644 src/meta/meta-keymap-description.h
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 096bee25ba..b7d92e6a4c 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -124,12 +124,9 @@ struct _MetaBackendClass
ClutterEventSequence *sequence,
MetaSequenceState state);
- void (* set_keymap_async) (MetaBackend *backend,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GTask *task);
+ void (* set_keymap_async) (MetaBackend *backend,
+ MetaKeymapDescription *description,
+ GTask *task);
struct xkb_keymap * (* get_keymap) (MetaBackend *backend);
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index ff01f58b9e..84e4d4cf25 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -1775,14 +1775,11 @@ meta_backend_set_keymap_finish (MetaBackend *backend,
}
void
-meta_backend_set_keymap_async (MetaBackend *backend,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+meta_backend_set_keymap_async (MetaBackend *backend,
+ MetaKeymapDescription *description,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GTask *task;
@@ -1790,10 +1787,7 @@ meta_backend_set_keymap_async (MetaBackend *backend,
g_task_set_source_tag (task, meta_backend_set_keymap_async);
META_BACKEND_GET_CLASS (backend)->set_keymap_async (backend,
- layouts,
- variants,
- options,
- model,
+ description,
task);
}
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
new file mode 100644
index 0000000000..2e9a6f8e45
--- /dev/null
+++ b/src/backends/meta-keymap-description-private.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "meta/meta-keymap-description.h"
+
+void meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
+ char **model,
+ char **layout,
+ char **variant,
+ char **options);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
new file mode 100644
index 0000000000..081fcf64d0
--- /dev/null
+++ b/src/backends/meta-keymap-description.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2025 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include "backends/meta-keymap-description-private.h"
+
+#include <glib-object.h>
+
+#include "backends/meta-keymap-utils.h"
+
+struct _MetaKeymapDescription
+{
+ gatomicrefcount ref_count;
+
+ char *rules;
+ char *model;
+ char *layout;
+ char *variant;
+ char *options;
+};
+
+#define DEFAULT_XKB_RULES_FILE "evdev"
+#define DEFAULT_XKB_MODEL "pc105+inet"
+
+G_DEFINE_BOXED_TYPE (MetaKeymapDescription, meta_keymap_description,
+ meta_keymap_description_ref,
+ meta_keymap_description_unref)
+
+static char *
+strdup_or_empty (const char *string)
+{
+ return string ? g_strdup (string) : g_strdup ("");
+}
+
+MetaKeymapDescription *
+meta_keymap_description_new_from_rules (const char *model,
+ const char *layout,
+ const char *variant,
+ const char *options)
+{
+ MetaKeymapDescription *keymap_description;
+
+ keymap_description = g_new0 (MetaKeymapDescription, 1);
+ g_atomic_ref_count_init (&keymap_description->ref_count);
+ keymap_description->model = model ? g_strdup (model)
+ : g_strdup (DEFAULT_XKB_MODEL);
+ keymap_description->layout = strdup_or_empty (layout);
+ keymap_description->variant = strdup_or_empty (variant);
+ keymap_description->options = strdup_or_empty (options);
+
+ return keymap_description;
+}
+
+MetaKeymapDescription *
+meta_keymap_description_ref (MetaKeymapDescription *keymap_description)
+{
+ g_atomic_ref_count_inc (&keymap_description->ref_count);
+ return keymap_description;
+}
+
+void
+meta_keymap_description_unref (MetaKeymapDescription *keymap_description)
+{
+ if (g_atomic_ref_count_dec (&keymap_description->ref_count))
+ {
+ g_free (keymap_description->model);
+ g_free (keymap_description->layout);
+ g_free (keymap_description->variant);
+ g_free (keymap_description->options);
+ g_free (keymap_description);
+ }
+}
+
+void
+meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
+ char **model,
+ char **layout,
+ char **variant,
+ char **options)
+{
+ *model = g_strdup (keymap_description->model);
+ *layout = g_strdup (keymap_description->layout);
+ *variant = g_strdup (keymap_description->variant);
+ *options = g_strdup (keymap_description->options);
+}
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index baca057b34..3e39efb098 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -334,19 +334,16 @@ set_keyboard_map_cb (GObject *source_object,
}
static void
-meta_backend_native_set_keymap_async (MetaBackend *backend,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GTask *task)
+meta_backend_native_set_keymap_async (MetaBackend *backend,
+ MetaKeymapDescription *description,
+ GTask *task)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_map_async (META_SEAT_NATIVE (seat),
- layouts, variants, options, model,
+ description,
g_task_get_cancellable (task),
set_keyboard_map_cb,
task);
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 1d88e1a131..63392531cd 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -29,6 +29,7 @@
#include "backends/native/meta-seat-native.h"
#include "backends/meta-cursor-tracker-private.h"
+#include "backends/meta-keymap-description-private.h"
#include "backends/meta-keymap-utils.h"
#include "backends/native/meta-barrier-native.h"
#include "backends/native/meta-input-thread.h"
@@ -36,6 +37,7 @@
#include "backends/native/meta-virtual-input-device-native.h"
#include "clutter/clutter-mutter.h"
#include "core/bell.h"
+#include "meta/meta-keymap-description.h"
#include "meta-private-enum-types.h"
@@ -55,13 +57,10 @@ static GParamSpec *props[N_PROPS] = { NULL };
G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT)
-static gboolean meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GCancellable *cancellable,
- GError **error);
+static gboolean meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
+ MetaKeymapDescription *description,
+ GCancellable *cancellable,
+ GError **error);
static gboolean
meta_seat_native_handle_event_post (ClutterSeat *seat,
@@ -155,6 +154,7 @@ static void
meta_seat_native_constructed (GObject *object)
{
MetaSeatNative *seat = META_SEAT_NATIVE (object);
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
g_autoptr (GError) error = NULL;
seat->impl = meta_seat_impl_new (seat, seat->seat_id, seat->flags);
@@ -171,8 +171,12 @@ meta_seat_native_constructed (GObject *object)
seat->core_pointer = meta_seat_impl_get_pointer (seat->impl);
seat->core_keyboard = meta_seat_impl_get_keyboard (seat->impl);
+ keymap_description = meta_keymap_description_new_from_rules (NULL,
+ "us",
+ NULL,
+ NULL);
if (!meta_seat_native_set_keyboard_map_sync (seat,
- "us", "", "", DEFAULT_XKB_MODEL,
+ keymap_description,
NULL, &error))
g_warning ("Failed to set keyboard map: %s", error->message);
@@ -583,21 +587,27 @@ set_impl_keyboard_map_cb (GObject *source_object,
* is pressed when calling this function.
*/
void
-meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
+ MetaKeymapDescription *description,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
g_autoptr (GTask) task = NULL;
struct xkb_keymap *keymap, *impl_keymap;
+ g_autofree char *layouts = NULL;
+ g_autofree char *variants = NULL;
+ g_autofree char *options = NULL;
+ g_autofree char *model = NULL;
task = g_task_new (G_OBJECT (seat), cancellable, callback, user_data);
g_task_set_source_tag (task, meta_seat_native_set_keyboard_map_async);
+ meta_keymap_description_get_rules (description,
+ &model,
+ &layouts,
+ &variants,
+ &options);
keymap = create_keymap (layouts, variants, options, model);
impl_keymap = create_keymap (layouts, variants, options, model);
@@ -640,13 +650,10 @@ set_keyboard_map_cb (GObject *source_object,
}
static gboolean
-meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GCancellable *cancellable,
- GError **error)
+meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
+ MetaKeymapDescription *description,
+ GCancellable *cancellable,
+ GError **error)
{
g_autoptr (GMainContext) main_context = NULL;
g_autoptr (GMainLoop) main_loop = NULL;
@@ -660,7 +667,7 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
g_task_set_task_data (task, main_loop, NULL);
meta_seat_native_set_keyboard_map_async (seat_native,
- layouts, variants, options, model,
+ description,
cancellable,
set_keyboard_map_cb, task);
g_main_loop_run (main_loop);
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index 9f300bad79..e0bd689a07 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -100,14 +100,11 @@ void meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callba
void meta_seat_native_release_devices (MetaSeatNative *seat);
void meta_seat_native_reclaim_devices (MetaSeatNative *seat);
-void meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
+ MetaKeymapDescription *description,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
gboolean meta_seat_native_set_keyboard_map_finish (MetaSeatNative *seat_native,
GAsyncResult *result,
diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c
index f5e0684588..094cec07ea 100644
--- a/src/compositor/plugins/default.c
+++ b/src/compositor/plugins/default.c
@@ -364,6 +364,7 @@ init_keymap (MetaDefaultPlugin *self,
g_autofree char *x11_options = NULL;
g_autofree char *x11_variant = NULL;
g_autofree char *x11_model = NULL;
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
@@ -414,11 +415,13 @@ init_keymap (MetaDefaultPlugin *self,
if (!g_variant_lookup (props, "X11Model", "s", &x11_model))
x11_model = g_strdup ("");
+ keymap_description = meta_keymap_description_new_from_rules (x11_model,
+ x11_layout,
+ x11_variant,
+ x11_options);
+
meta_backend_set_keymap_async (backend,
- x11_layout,
- x11_variant,
- x11_options,
- x11_model,
+ keymap_description,
NULL, NULL, NULL);
}
diff --git a/src/meson.build b/src/meson.build
index 159e207153..e7824f502e 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -243,6 +243,8 @@ mutter_sources = [
'backends/meta-input-settings-private.h',
'backends/meta-input-settings-dummy.c',
'backends/meta-input-settings-dummy.h',
+ 'backends/meta-keymap-description.c',
+ 'backends/meta-keymap-description-private.h',
'backends/meta-keymap-utils.c',
'backends/meta-keymap-utils.h',
'backends/meta-logical-monitor.c',
diff --git a/src/meta/meson.build b/src/meta/meson.build
index 601b020044..8374441dd2 100644
--- a/src/meta/meson.build
+++ b/src/meta/meson.build
@@ -24,6 +24,7 @@ mutter_public_headers = [
'meta-external-constraint.h',
'meta-idle-monitor.h',
'meta-inhibit-shortcuts-dialog.h',
+ 'meta-keymap-description.h',
'meta-later.h',
'meta-launch-context.h',
'meta-logical-monitor.h',
diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h
index 5511acbeec..74ad2bfebf 100644
--- a/src/meta/meta-backend.h
+++ b/src/meta/meta-backend.h
@@ -27,6 +27,7 @@
#include "clutter/clutter.h"
#include "meta/meta-dnd.h"
#include "meta/meta-idle-monitor.h"
+#include "meta/meta-keymap-description.h"
#include "meta/meta-logical-monitor.h"
#include "meta/meta-monitor-manager.h"
#include "meta/meta-orientation-manager.h"
@@ -48,14 +49,11 @@ gboolean meta_backend_set_keymap_finish (MetaBackend *backend,
GError **error);
META_EXPORT
-void meta_backend_set_keymap_async (MetaBackend *backend,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void meta_backend_set_keymap_async (MetaBackend *backend,
+ MetaKeymapDescription *description,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
META_EXPORT
gboolean meta_backend_set_keymap_layout_group_finish (MetaBackend *backend,
diff --git a/src/meta/meta-keymap-description.h b/src/meta/meta-keymap-description.h
new file mode 100644
index 0000000000..32e9ef6d2d
--- /dev/null
+++ b/src/meta/meta-keymap-description.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2025 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "meta/util.h"
+
+typedef struct _MetaKeymapDescription MetaKeymapDescription;
+
+#define META_TYPE_KEYMAP_DESCRIPTION (meta_keymap_description_get_type ())
+
+META_EXPORT
+GType meta_keymap_description_get_type (void) G_GNUC_CONST;
+
+META_EXPORT
+MetaKeymapDescription * meta_keymap_description_new_from_rules (const char *model,
+ const char *layout,
+ const char *variant,
+ const char *options);
+
+META_EXPORT
+MetaKeymapDescription * meta_keymap_description_ref (MetaKeymapDescription *keymap_description);
+
+META_EXPORT
+void meta_keymap_description_unref (MetaKeymapDescription *keymap_description);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKeymapDescription,
+ meta_keymap_description_unref);
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index bca99da74d..8d93dababf 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -110,6 +110,7 @@ meta_test_native_keyboard_map_set_async (void)
1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT);
ModMaskTuple expected_mods = { alt_mask, 0, 0 };
ModMaskTuple *expected_mods_ptr = &expected_mods;
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
struct xkb_keymap *new_xkb_keymap;
gboolean done = FALSE;
gpointer expected_next_handler;
@@ -155,11 +156,13 @@ meta_test_native_keyboard_map_set_async (void)
&expected_next_handler);
expected_next_handler = (gpointer) on_keymap_changed;
- meta_backend_set_keymap_async (backend,
- "us",
- "dvorak-alt-intl",
- NULL, NULL, NULL,
- set_keymap_cb, &done);
+ keymap_description =
+ meta_keymap_description_new_from_rules (NULL,
+ "us",
+ "dvorak-alt-intl",
+ NULL);
+ meta_backend_set_keymap_async (backend, keymap_description,
+ NULL, set_keymap_cb, &done);
g_assert_true (xkb_keymap == meta_backend_get_keymap (backend));
@@ -191,9 +194,9 @@ meta_test_native_keyboard_map_change_layout (void)
{
MetaBackend *backend = meta_context_get_backend (test_context);
ClutterSeat *seat = meta_backend_get_default_seat (backend);
-
g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL;
struct xkb_keymap *xkb_keymap = meta_backend_get_keymap (backend);
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
struct xkb_keymap *new_xkb_keymap;
gboolean done = FALSE;
@@ -202,12 +205,13 @@ meta_test_native_keyboard_map_change_layout (void)
xkb_keymap_ref (xkb_keymap);
- meta_backend_set_keymap_async (backend,
- "us,ua",
- NULL,
- "grp:caps_select",
- NULL, NULL,
- set_keymap_cb, &done);
+ keymap_description =
+ meta_keymap_description_new_from_rules (NULL,
+ "us,ua",
+ NULL,
+ "grp:caps_select");
+ meta_backend_set_keymap_async (backend, keymap_description,
+ NULL, set_keymap_cb, &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
@@ -279,14 +283,17 @@ static void
meta_test_native_keyboard_map_set_layout_index (void)
{
MetaBackend *backend = meta_context_get_backend (test_context);
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
gboolean done = FALSE;
struct xkb_keymap *keymap;
- meta_backend_set_keymap_async (backend,
- "us,se",
- "dvorak-alt-intl,svdvorak",
- NULL, NULL, NULL,
- set_keymap_cb, &done);
+ keymap_description =
+ meta_keymap_description_new_from_rules (NULL,
+ "us,se",
+ "dvorak-alt-intl,svdvorak",
+ NULL);
+ meta_backend_set_keymap_async (backend, keymap_description,
+ NULL, set_keymap_cb, &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
diff --git a/src/tests/remote-desktop-tests.c b/src/tests/remote-desktop-tests.c
index d006cecdda..04979afa66 100644
--- a/src/tests/remote-desktop-tests.c
+++ b/src/tests/remote-desktop-tests.c
@@ -70,12 +70,17 @@ remote_desktop_test_client_command (int argc,
const char *layout = argv[1];
const char *variant = argv[2];
g_autoptr (GMainContext) main_context = NULL;
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
gboolean done = FALSE;
g_debug ("Switching keyboard layout to %s, %s", layout, variant);
main_context = g_main_context_new ();
g_main_context_push_thread_default (main_context);
- meta_backend_set_keymap_async (backend, layout, variant, "", "",
+ keymap_description = meta_keymap_description_new_from_rules (NULL,
+ layout,
+ variant,
+ NULL);
+ meta_backend_set_keymap_async (backend, keymap_description,
NULL, set_keymap_cb, &done);
while (!done)
g_main_context_iteration (main_context, TRUE);
--
2.54.0
From d2a5ffe3f926391a80fee07e4a5f1dfc5dd8b033 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 17:14:12 +0200
Subject: [PATCH 07/32] keymap-description: Add helper for creating xkb_keymap
instances
Will be useful when there are different description sources and not only
rules based methods of creating a keymap.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 138bffbd16e84143e4d2f3a8db3875a5da5f1bc6)
---
.../meta-keymap-description-private.h | 3 ++
src/backends/meta-keymap-description.c | 37 +++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index 2e9a6f8e45..47e2234322 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -25,3 +25,6 @@ void meta_keymap_description_get_rules (MetaKeymapDescription *keymap_descripti
char **layout,
char **variant,
char **options);
+
+struct xkb_keymap * meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
+ GError **error);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index 081fcf64d0..39af564a0c 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -99,3 +99,40 @@ meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
*variant = g_strdup (keymap_description->variant);
*options = g_strdup (keymap_description->options);
}
+
+struct xkb_keymap *
+meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
+ GError **error)
+{
+ struct xkb_rule_names names;
+ struct xkb_context *xkb_context;
+ struct xkb_keymap *xkb_keymap;
+
+ names.rules = DEFAULT_XKB_RULES_FILE;
+ names.model = keymap_description->model;
+ names.layout = keymap_description->layout;
+ names.variant = keymap_description->variant;
+ names.options = keymap_description->options;
+
+ xkb_context = meta_create_xkb_context ();
+ xkb_keymap = xkb_keymap_new_from_names (xkb_context,
+ &names,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_context_unref (xkb_context);
+
+ if (!xkb_keymap)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to create XKB keymap with "
+ "rules=%s, model=%s, layout=%s, "
+ "variant=%s, options=%s",
+ keymap_description->rules,
+ keymap_description->model,
+ keymap_description->layout,
+ keymap_description->variant,
+ keymap_description->options);
+ return NULL;
+ }
+
+ return xkb_keymap;
+}
--
2.54.0
From dae726791082e3e4b37c720f368c30aaca299ad5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 17:12:38 +0200
Subject: [PATCH 08/32] seat/native: Use new xkb_keymap constructor from
description
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 5fc5f363805e54c7c3fbf890b1539a72438ab9ad)
---
.../meta-keymap-description-private.h | 6 ---
src/backends/meta-keymap-description.c | 13 -----
src/backends/native/meta-seat-native.c | 51 ++++---------------
3 files changed, 10 insertions(+), 60 deletions(-)
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index 47e2234322..3cacfe6561 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -20,11 +20,5 @@
#include "meta/meta-keymap-description.h"
-void meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
- char **model,
- char **layout,
- char **variant,
- char **options);
-
struct xkb_keymap * meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
GError **error);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index 39af564a0c..cd93c543e3 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -87,19 +87,6 @@ meta_keymap_description_unref (MetaKeymapDescription *keymap_description)
}
}
-void
-meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
- char **model,
- char **layout,
- char **variant,
- char **options)
-{
- *model = g_strdup (keymap_description->model);
- *layout = g_strdup (keymap_description->layout);
- *variant = g_strdup (keymap_description->variant);
- *options = g_strdup (keymap_description->options);
-}
-
struct xkb_keymap *
meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
GError **error)
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 63392531cd..905fa13ce0 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -513,29 +513,6 @@ meta_seat_native_reclaim_devices (MetaSeatNative *seat)
seat->released = FALSE;
}
-static struct xkb_keymap *
-create_keymap (const char *layouts,
- const char *variants,
- const char *options,
- const char *model)
-{
- struct xkb_rule_names names;
- struct xkb_keymap *keymap;
- struct xkb_context *context;
-
- names.rules = DEFAULT_XKB_RULES_FILE;
- names.model = model;
- names.layout = layouts;
- names.variant = variants;
- names.options = options;
-
- context = meta_create_xkb_context ();
- keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
- xkb_context_unref (context);
-
- return keymap;
-}
-
gboolean
meta_seat_native_set_keyboard_map_finish (MetaSeatNative *seat_native,
GAsyncResult *result,
@@ -595,30 +572,22 @@ meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
{
g_autoptr (GTask) task = NULL;
struct xkb_keymap *keymap, *impl_keymap;
- g_autofree char *layouts = NULL;
- g_autofree char *variants = NULL;
- g_autofree char *options = NULL;
- g_autofree char *model = NULL;
+ g_autoptr (GError) error = NULL;
task = g_task_new (G_OBJECT (seat), cancellable, callback, user_data);
g_task_set_source_tag (task, meta_seat_native_set_keyboard_map_async);
- meta_keymap_description_get_rules (description,
- &model,
- &layouts,
- &variants,
- &options);
- keymap = create_keymap (layouts, variants, options, model);
- impl_keymap = create_keymap (layouts, variants, options, model);
-
+ keymap = meta_keymap_description_create_xkb_keymap (description, &error);
if (keymap == NULL)
{
- g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Unable to load configured keymap: "
- "rules=%s, model=%s, ""layout=%s, "
- "variant=%s, options=%s",
- DEFAULT_XKB_RULES_FILE, model, layouts,
- variants, options);
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ impl_keymap = meta_keymap_description_create_xkb_keymap (description, &error);
+ if (impl_keymap == NULL)
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
return;
}
--
2.54.0
From 520b5a3d4f46900506a1e0df3cd1dfcf7699a008 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 21:36:32 +0200
Subject: [PATCH 09/32] keybindings: Create xkb_keymap from keymap description
This hides xkb_keymap specific details out of sight.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit e0d847357951f107790c421eb772c7ab89be6834)
---
src/core/keybindings.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 551a156e50..0f475eae3b 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -30,7 +30,7 @@
#include "config.h"
#include "backends/meta-backend-private.h"
-#include "backends/meta-keymap-utils.h"
+#include "backends/meta-keymap-description-private.h"
#include "backends/meta-logical-monitor-private.h"
#include "backends/meta-monitor-manager-private.h"
#include "compositor/compositor-private.h"
@@ -766,19 +766,21 @@ clear_active_keyboard_layouts (MetaKeyBindingManager *keys)
static MetaKeyBindingKeyboardLayout
create_us_layout (void)
{
- struct xkb_rule_names names;
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
+ g_autoptr (GError) error = NULL;
struct xkb_keymap *keymap;
- struct xkb_context *context;
- names.rules = DEFAULT_XKB_RULES_FILE;
- names.model = DEFAULT_XKB_MODEL;
- names.layout = "us";
- names.variant = "";
- names.options = "";
-
- context = meta_create_xkb_context ();
- keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
- xkb_context_unref (context);
+ keymap_description = meta_keymap_description_new_from_rules (NULL,
+ "us",
+ NULL,
+ NULL);
+ keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
+ &error);
+ if (!keymap)
+ {
+ g_warning ("Failed to create us keybinding layout: %s", error->message);
+ return (MetaKeyBindingKeyboardLayout) {};
+ }
return (MetaKeyBindingKeyboardLayout) {
.keymap = keymap,
--
2.54.0
From 505c26321ac34934eb45c2555090ece23ca751e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 21:11:50 +0200
Subject: [PATCH 10/32] seat/native: Pass keymap description instead of
xkb_keymap
This means the description is available in places it will later be
useful to have. Right now, there are no functional changes.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 9df69e82ada1dc620c71d12faca3ffb36f9525e9)
---
src/backends/native/meta-seat-impl.c | 37 +++++++++++++++++---------
src/backends/native/meta-seat-impl.h | 10 +++----
src/backends/native/meta-seat-native.c | 33 ++++++++++-------------
3 files changed, 44 insertions(+), 36 deletions(-)
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index 0a6aae3cf0..f89dfc90d9 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -35,6 +35,7 @@
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-fd-source.h"
+#include "backends/meta-keymap-description-private.h"
#include "backends/native/meta-backend-native-private.h"
#include "backends/native/meta-barrier-native.h"
#include "backends/native/meta-device-pool.h"
@@ -3819,16 +3820,28 @@ static gboolean
set_keyboard_map (GTask *task)
{
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
- struct xkb_keymap *xkb_keymap = g_task_get_task_data (task);
+ MetaKeymapDescription *keymap_description = g_task_get_task_data (task);
MetaKeymapNative *keymap;
+ g_autoptr (GError) error = NULL;
+ struct xkb_keymap *xkb_keymap;
+
+ g_task_set_priority (task, G_PRIORITY_HIGH);
keymap = seat_impl->keymap;
- meta_keymap_native_set_keyboard_map_in_impl (keymap, xkb_keymap);
- g_task_set_priority (task, G_PRIORITY_HIGH);
- g_task_return_boolean (task, TRUE);
+ xkb_keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
+ &error);
+ if (!xkb_keymap)
+ {
+ g_prefix_error (&error, "Unable to load configured keymap: ");
+ g_task_return_error (task, g_steal_pointer (&error));
+ return G_SOURCE_REMOVE;
+ }
+
+ meta_keymap_native_set_keyboard_map_in_impl (keymap, xkb_keymap);
meta_seat_impl_update_xkb_state_in_impl (seat_impl);
+ g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
@@ -3847,22 +3860,22 @@ set_keyboard_map (GTask *task)
* is pressed when calling this function.
*/
void
-meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
- struct xkb_keymap *xkb_keymap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GTask *task;
g_return_if_fail (META_IS_SEAT_IMPL (seat_impl));
- g_return_if_fail (xkb_keymap != NULL);
+ g_return_if_fail (keymap_description);
task = g_task_new (seat_impl, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_seat_impl_set_keyboard_map_async);
g_task_set_task_data (task,
- xkb_keymap_ref (xkb_keymap),
- (GDestroyNotify) xkb_keymap_unref);
+ meta_keymap_description_ref (keymap_description),
+ (GDestroyNotify) meta_keymap_description_unref);
meta_seat_impl_run_input_task (seat_impl, task, (GSourceFunc) set_keyboard_map);
g_object_unref (task);
}
diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h
index 24d0405062..3637627a67 100644
--- a/src/backends/native/meta-seat-impl.h
+++ b/src/backends/native/meta-seat-impl.h
@@ -189,11 +189,11 @@ gboolean meta_seat_impl_set_keyboard_map_finish (MetaSeatImpl *seat_impl,
GAsyncResult *result,
GError **error);
-void meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
- struct xkb_keymap *keymap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
gboolean meta_seat_impl_set_keyboard_layout_index_finish (MetaSeatImpl *seat_impl,
GAsyncResult *result,
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 905fa13ce0..dc2e6683a4 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -536,6 +536,7 @@ set_impl_keyboard_map_cb (GObject *source_object,
g_autoptr (GTask) task = G_TASK (user_data);
g_autoptr (GError) error = NULL;
MetaSeatNative *seat_native;
+ MetaKeymapDescription *keymap_description;
struct xkb_keymap *keymap;
if (!meta_seat_impl_set_keyboard_map_finish (seat_impl, result, &error))
@@ -545,7 +546,14 @@ set_impl_keyboard_map_cb (GObject *source_object,
}
seat_native = META_SEAT_NATIVE (g_task_get_source_object (task));
- keymap = g_task_get_task_data (task);
+ keymap_description = g_task_get_task_data (task);
+ keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
+ &error);
+ if (!keymap)
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
g_clear_pointer (&seat_native->xkb_keymap, xkb_keymap_unref);
seat_native->xkb_keymap = xkb_keymap_ref (keymap);
@@ -571,33 +579,20 @@ meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
gpointer user_data)
{
g_autoptr (GTask) task = NULL;
- struct xkb_keymap *keymap, *impl_keymap;
g_autoptr (GError) error = NULL;
task = g_task_new (G_OBJECT (seat), cancellable, callback, user_data);
g_task_set_source_tag (task, meta_seat_native_set_keyboard_map_async);
- keymap = meta_keymap_description_create_xkb_keymap (description, &error);
- if (keymap == NULL)
- {
- g_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- impl_keymap = meta_keymap_description_create_xkb_keymap (description, &error);
- if (impl_keymap == NULL)
- {
- g_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- g_task_set_task_data (task, keymap, (GDestroyNotify) xkb_keymap_unref);
+ g_task_set_task_data (task,
+ meta_keymap_description_ref (description),
+ (GDestroyNotify) meta_keymap_description_unref);
- meta_seat_impl_set_keyboard_map_async (seat->impl, impl_keymap,
+ meta_seat_impl_set_keyboard_map_async (seat->impl,
+ description,
cancellable,
set_impl_keyboard_map_cb,
g_object_ref (task));
- xkb_keymap_unref (impl_keymap);
}
static void
--
2.54.0
From 248e82f10e7f12b2bb86bc4659d5992c89ea641e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Mon, 6 Oct 2025 11:41:07 +0200
Subject: [PATCH 11/32] tests/remote-desktop-tests: Don't use nested context
when setting keymap
This will fail when the keymap related state is set via signals that
gets emitted from callbacks from the impl thread, that won't know about
the current thread default context.
It should also be harmless, we won't read the next line until the
function returns, so there should be no risk of re-entry.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 2509ba34aad134ecfc9ad33dcfe939c8dd0bc161)
---
src/tests/remote-desktop-tests.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/tests/remote-desktop-tests.c b/src/tests/remote-desktop-tests.c
index 04979afa66..a2ce8ce388 100644
--- a/src/tests/remote-desktop-tests.c
+++ b/src/tests/remote-desktop-tests.c
@@ -69,13 +69,10 @@ remote_desktop_test_client_command (int argc,
MetaBackend *backend = meta_context_get_backend (test_context);
const char *layout = argv[1];
const char *variant = argv[2];
- g_autoptr (GMainContext) main_context = NULL;
g_autoptr (MetaKeymapDescription) keymap_description = NULL;
gboolean done = FALSE;
g_debug ("Switching keyboard layout to %s, %s", layout, variant);
- main_context = g_main_context_new ();
- g_main_context_push_thread_default (main_context);
keymap_description = meta_keymap_description_new_from_rules (NULL,
layout,
variant,
@@ -83,8 +80,7 @@ remote_desktop_test_client_command (int argc,
meta_backend_set_keymap_async (backend, keymap_description,
NULL, set_keymap_cb, &done);
while (!done)
- g_main_context_iteration (main_context, TRUE);
- g_main_context_pop_thread_default (main_context);
+ g_main_context_iteration (NULL, TRUE);
return TRUE;
}
--
2.54.0
From 60efa23fa5efe2ca105aef4fa21c653beec30f2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 21:49:24 +0200
Subject: [PATCH 12/32] backend/native: Emit 'keymap-changed' via signal on the
ClutterKeymap
This will allow proper ordering of events (keymap & layout index
changes) if the index also changes at the same time as the keymap.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit ce7f26e16f5e2e7c4e73e2936818f8b528c1b37d)
---
src/backends/native/meta-backend-native.c | 10 +-
.../native/meta-keymap-native-private.h | 6 +-
src/backends/native/meta-keymap-native.c | 61 ++++++++-
src/backends/native/meta-seat-impl.c | 5 +-
src/backends/native/meta-seat-native.c | 126 +++++++++++++-----
src/backends/native/meta-seat-native.h | 1 +
6 files changed, 164 insertions(+), 45 deletions(-)
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 3e39efb098..95dbfca41e 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -207,6 +207,7 @@ meta_backend_native_init_post (MetaBackend *backend,
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaA11yManager *a11y_manager = meta_backend_get_a11y_manager (backend);
+ ClutterSeat *seat;
g_clear_pointer (&priv->startup_render_devices,
g_hash_table_unref);
@@ -225,6 +226,11 @@ meta_backend_native_init_post (MetaBackend *backend,
"backend", backend,
NULL);
+ seat = meta_backend_get_default_seat (backend);
+ g_signal_connect_swapped (seat, "keymap-changed",
+ G_CALLBACK (meta_backend_notify_keymap_changed),
+ backend);
+
return TRUE;
}
@@ -319,7 +325,6 @@ set_keyboard_map_cb (GObject *source_object,
MetaSeatNative *seat_native = META_SEAT_NATIVE (source_object);
g_autoptr (GTask) task = G_TASK (user_data);
g_autoptr (GError) error = NULL;
- MetaBackend *backend;
if (!meta_seat_native_set_keyboard_map_finish (seat_native, result, &error))
{
@@ -327,9 +332,6 @@ set_keyboard_map_cb (GObject *source_object,
return;
}
- backend = META_BACKEND (g_task_get_source_object (task));
- meta_backend_notify_keymap_changed (backend);
-
g_task_return_boolean (task, TRUE);
}
diff --git a/src/backends/native/meta-keymap-native-private.h b/src/backends/native/meta-keymap-native-private.h
index 318485a102..2084393d5f 100644
--- a/src/backends/native/meta-keymap-native-private.h
+++ b/src/backends/native/meta-keymap-native-private.h
@@ -25,8 +25,10 @@
#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h""
#endif /* META_INPUT_THREAD_H_INSIDE */
-void meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
- struct xkb_keymap *xkb_keymap);
+void meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
+ MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ struct xkb_keymap *xkb_keymap);
struct xkb_keymap * meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap);
diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c
index 8d1d804c12..770f0cb0d0 100644
--- a/src/backends/native/meta-keymap-native.c
+++ b/src/backends/native/meta-keymap-native.c
@@ -29,6 +29,15 @@ static const char *option_xkb_layout = "us";
static const char *option_xkb_variant = "";
static const char *option_xkb_options = "";
+enum
+{
+ KEYMAP_CHANGED,
+
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
typedef struct _MetaKeymapNative MetaKeymapNative;
struct _MetaKeymapNative
@@ -68,6 +77,14 @@ meta_keymap_native_class_init (MetaKeymapNativeClass *klass)
object_class->finalize = meta_keymap_native_finalize;
keymap_class->get_direction = meta_keymap_native_get_direction;
+
+ signals[KEYMAP_CHANGED] =
+ g_signal_new ("keymap-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ META_TYPE_KEYMAP_DESCRIPTION);
}
static void
@@ -88,14 +105,54 @@ meta_keymap_native_init (MetaKeymapNative *keymap)
xkb_context_unref (ctx);
}
+typedef struct
+{
+ MetaKeymapNative *keymap_native;
+
+ MetaKeymapDescription *keymap_description;
+} UpdateKeymapData;
+
+static void
+update_keymap_data_free (gpointer user_data)
+{
+ UpdateKeymapData *data = user_data;
+
+ meta_keymap_description_unref (data->keymap_description);
+ g_free (data);
+}
+
+static gboolean
+update_keymap_in_main (gpointer user_data)
+{
+ UpdateKeymapData *data = user_data;
+ MetaKeymapNative *keymap_native = data->keymap_native;
+
+ g_signal_emit (keymap_native, signals[KEYMAP_CHANGED], 0,
+ data->keymap_description);
+
+ return G_SOURCE_REMOVE;
+}
+
void
-meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
- struct xkb_keymap *xkb_keymap)
+meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
+ MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ struct xkb_keymap *xkb_keymap)
{
+ UpdateKeymapData *data;
+
g_return_if_fail (xkb_keymap != NULL);
g_clear_pointer (&keymap->impl.keymap, xkb_keymap_unref);
keymap->impl.keymap = xkb_keymap_ref (xkb_keymap);
+
+ data = g_new0 (UpdateKeymapData, 1);
+ data->keymap_native = keymap;
+ data->keymap_description = meta_keymap_description_ref (keymap_description);
+
+ meta_seat_impl_queue_main_thread_idle (seat_impl,
+ update_keymap_in_main,
+ data, update_keymap_data_free);
}
struct xkb_keymap *
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index f89dfc90d9..1a54cfe00c 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3838,7 +3838,10 @@ set_keyboard_map (GTask *task)
return G_SOURCE_REMOVE;
}
- meta_keymap_native_set_keyboard_map_in_impl (keymap, xkb_keymap);
+ meta_keymap_native_set_keyboard_map_in_impl (keymap,
+ seat_impl,
+ keymap_description,
+ xkb_keymap);
meta_seat_impl_update_xkb_state_in_impl (seat_impl);
g_task_return_boolean (task, TRUE);
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index dc2e6683a4..9be0bd7ce1 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -55,6 +55,15 @@ enum
static GParamSpec *props[N_PROPS] = { NULL };
+enum
+{
+ KEYMAP_CHANGED,
+
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT)
static gboolean meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
@@ -150,12 +159,44 @@ keymap_state_changed_cb (MetaSeatNative *seat_native,
}
}
+static void
+on_keymap_changed (MetaKeymapNative *keymap_native,
+ MetaKeymapDescription *keymap_description,
+ MetaSeatNative *seat_native)
+{
+ g_autoptr (GError) error = NULL;
+ struct xkb_keymap *xkb_keymap;
+
+ if (seat_native->keymap_description == keymap_description)
+ return;
+
+ xkb_keymap =
+ meta_keymap_description_create_xkb_keymap (keymap_description,
+ &error);
+ if (!xkb_keymap)
+ {
+ g_warning ("Failed to create xkb_keymap for seat: %s", error->message);
+ return;
+ }
+
+ g_clear_pointer (&seat_native->keymap_description,
+ meta_keymap_description_unref);
+ seat_native->keymap_description =
+ meta_keymap_description_ref (keymap_description);
+
+ g_clear_pointer (&seat_native->xkb_keymap, xkb_keymap_unref);
+ seat_native->xkb_keymap = xkb_keymap;
+
+ g_signal_emit (seat_native, signals[KEYMAP_CHANGED], 0);
+}
+
static void
meta_seat_native_constructed (GObject *object)
{
MetaSeatNative *seat = META_SEAT_NATIVE (object);
g_autoptr (MetaKeymapDescription) keymap_description = NULL;
g_autoptr (GError) error = NULL;
+ ClutterKeymap *keymap;
seat->impl = meta_seat_impl_new (seat, seat->seat_id, seat->flags);
meta_seat_impl_setup (seat->impl);
@@ -171,6 +212,10 @@ meta_seat_native_constructed (GObject *object)
seat->core_pointer = meta_seat_impl_get_pointer (seat->impl);
seat->core_keyboard = meta_seat_impl_get_keyboard (seat->impl);
+ keymap = clutter_seat_get_keymap (CLUTTER_SEAT (seat));
+ g_signal_connect (keymap, "keymap-changed",
+ G_CALLBACK (on_keymap_changed), seat);
+
keymap_description = meta_keymap_description_new_from_rules (NULL,
"us",
NULL,
@@ -241,6 +286,8 @@ meta_seat_native_dispose (GObject *object)
{
MetaSeatNative *seat = META_SEAT_NATIVE (object);
+ g_clear_pointer (&seat->keymap_description,
+ meta_keymap_description_unref);
g_clear_pointer (&seat->xkb_keymap, xkb_keymap_unref);
g_clear_object (&seat->core_pointer);
g_clear_object (&seat->core_keyboard);
@@ -447,6 +494,13 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass)
g_object_class_override_property (object_class, PROP_TOUCH_MODE,
"touch-mode");
+
+ signals[KEYMAP_CHANGED] =
+ g_signal_new ("keymap-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
}
static void
@@ -535,9 +589,6 @@ set_impl_keyboard_map_cb (GObject *source_object,
MetaSeatImpl *seat_impl = META_SEAT_IMPL (source_object);
g_autoptr (GTask) task = G_TASK (user_data);
g_autoptr (GError) error = NULL;
- MetaSeatNative *seat_native;
- MetaKeymapDescription *keymap_description;
- struct xkb_keymap *keymap;
if (!meta_seat_impl_set_keyboard_map_finish (seat_impl, result, &error))
{
@@ -545,19 +596,6 @@ set_impl_keyboard_map_cb (GObject *source_object,
return;
}
- seat_native = META_SEAT_NATIVE (g_task_get_source_object (task));
- keymap_description = g_task_get_task_data (task);
- keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
- &error);
- if (!keymap)
- {
- g_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- g_clear_pointer (&seat_native->xkb_keymap, xkb_keymap_unref);
- seat_native->xkb_keymap = xkb_keymap_ref (keymap);
-
g_task_return_boolean (task, TRUE);
}
@@ -579,15 +617,10 @@ meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
gpointer user_data)
{
g_autoptr (GTask) task = NULL;
- g_autoptr (GError) error = NULL;
task = g_task_new (G_OBJECT (seat), cancellable, callback, user_data);
g_task_set_source_tag (task, meta_seat_native_set_keyboard_map_async);
- g_task_set_task_data (task,
- meta_keymap_description_ref (description),
- (GDestroyNotify) meta_keymap_description_unref);
-
meta_seat_impl_set_keyboard_map_async (seat->impl,
description,
cancellable,
@@ -596,20 +629,23 @@ meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
}
static void
-set_keyboard_map_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+sync_set_impl_keyboard_map_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- MetaSeatNative *seat_native = META_SEAT_NATIVE (source_object);
+ MetaSeatImpl *seat_impl = META_SEAT_IMPL (source_object);
+ g_autoptr (GError) error = NULL;
GTask *task = G_TASK (user_data);
GMainLoop *main_loop = g_task_get_task_data (task);
- g_autoptr (GError) error = NULL;
- if (!meta_seat_native_set_keyboard_map_finish (seat_native, result, &error))
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
+ if (!meta_seat_impl_set_keyboard_map_finish (seat_impl, result, &error))
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ g_main_loop_quit (main_loop);
+ return;
+ }
+ g_task_return_boolean (task, TRUE);
g_main_loop_quit (main_loop);
}
@@ -622,22 +658,40 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
g_autoptr (GMainContext) main_context = NULL;
g_autoptr (GMainLoop) main_loop = NULL;
g_autoptr (GTask) task = NULL;
+ struct xkb_keymap *xkb_keymap;
main_context = g_main_context_new ();
main_loop = g_main_loop_new (main_context, FALSE);
g_main_context_push_thread_default (main_context);
- task = g_task_new (G_OBJECT (seat_native), NULL, NULL, NULL);
+ task = g_task_new (NULL, NULL, NULL, NULL);
g_task_set_task_data (task, main_loop, NULL);
- meta_seat_native_set_keyboard_map_async (seat_native,
- description,
- cancellable,
- set_keyboard_map_cb, task);
+ meta_seat_impl_set_keyboard_map_async (seat_native->impl,
+ description,
+ cancellable,
+ sync_set_impl_keyboard_map_cb,
+ task);
g_main_loop_run (main_loop);
g_main_context_pop_thread_default (main_context);
- return g_task_propagate_boolean (task, error);
+ if (!g_task_propagate_boolean (task, error))
+ return FALSE;
+
+ xkb_keymap =
+ meta_keymap_description_create_xkb_keymap (description,
+ error);
+ if (!xkb_keymap)
+ return FALSE;
+
+ g_clear_pointer (&seat_native->xkb_keymap, xkb_keymap_unref);
+ seat_native->xkb_keymap = xkb_keymap_ref (xkb_keymap);
+
+ g_clear_pointer (&seat_native->keymap_description,
+ meta_keymap_description_unref);
+ seat_native->keymap_description = meta_keymap_description_ref (description);
+
+ return TRUE;
}
/**
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index e0bd689a07..fc0663086e 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -50,6 +50,7 @@ struct _MetaSeatNative
GList *devices;
struct xkb_keymap *xkb_keymap;
xkb_layout_index_t xkb_layout_index;
+ MetaKeymapDescription *keymap_description;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
--
2.54.0
From b024281a74510eaef821cdc6c9bb2f660d1fcae2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 9 Dec 2025 22:10:35 +0100
Subject: [PATCH 13/32] keymap/native: Move out modifier handling to helpers
This will make it easier to update modifiers from other places later.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit a2eeb8959e6d3981673fe3d47f909e98877ebcf4)
---
src/backends/native/meta-keymap-native.c | 85 +++++++++++++++---------
1 file changed, 52 insertions(+), 33 deletions(-)
diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c
index 770f0cb0d0..ec69950e0a 100644
--- a/src/backends/native/meta-keymap-native.c
+++ b/src/backends/native/meta-keymap-native.c
@@ -49,6 +49,15 @@ struct _MetaKeymapNative
} impl;
};
+typedef struct
+{
+ xkb_mod_mask_t depressed_mods;
+ xkb_mod_mask_t latched_mods;
+ xkb_mod_mask_t locked_mods;
+
+ xkb_layout_index_t effective_layout_group;
+} ModifierState;
+
G_DEFINE_TYPE (MetaKeymapNative, meta_keymap_native,
CLUTTER_TYPE_KEYMAP)
@@ -105,6 +114,46 @@ meta_keymap_native_init (MetaKeymapNative *keymap)
xkb_context_unref (ctx);
}
+static ModifierState
+calculate_modifier_state (struct xkb_state *xkb_state)
+{
+ return (ModifierState) {
+ .depressed_mods =
+ xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED),
+ .latched_mods =
+ xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LATCHED),
+ .locked_mods =
+ xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED),
+ .effective_layout_group =
+ xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE),
+ };
+}
+
+static void
+update_state_from_modifier_state (MetaKeymapNative *keymap_native,
+ ModifierState *modifier_state)
+{
+ gboolean caps_lock_state;
+ gboolean num_lock_state;
+
+ num_lock_state =
+ !!((modifier_state->latched_mods | modifier_state->locked_mods) &
+ (1 << xkb_keymap_mod_get_index (keymap_native->impl.keymap,
+ XKB_MOD_NAME_NUM)));
+ caps_lock_state =
+ !!((modifier_state->latched_mods | modifier_state->locked_mods) &
+ (1 << xkb_keymap_mod_get_index (keymap_native->impl.keymap,
+ XKB_MOD_NAME_CAPS)));
+
+ clutter_keymap_update_state (CLUTTER_KEYMAP (keymap_native),
+ caps_lock_state,
+ num_lock_state,
+ modifier_state->effective_layout_group,
+ modifier_state->depressed_mods,
+ modifier_state->latched_mods,
+ modifier_state->locked_mods);
+}
+
typedef struct
{
MetaKeymapNative *keymap_native;
@@ -165,11 +214,7 @@ typedef struct
{
MetaKeymapNative *keymap_native;
- xkb_mod_mask_t depressed_mods;
- xkb_mod_mask_t latched_mods;
- xkb_mod_mask_t locked_mods;
-
- xkb_layout_index_t effective_layout_group;
+ ModifierState modifier_state;
} UpdateLockedModifierStateData;
static gboolean
@@ -177,25 +222,8 @@ update_state_in_main (gpointer user_data)
{
UpdateLockedModifierStateData *data = user_data;
MetaKeymapNative *keymap_native = data->keymap_native;
- gboolean caps_lock_state;
- gboolean num_lock_state;
- num_lock_state =
- !!((data->latched_mods | data->locked_mods) &
- (1 << xkb_keymap_mod_get_index (keymap_native->impl.keymap,
- XKB_MOD_NAME_NUM)));
- caps_lock_state =
- !!((data->latched_mods | data->locked_mods) &
- (1 << xkb_keymap_mod_get_index (keymap_native->impl.keymap,
- XKB_MOD_NAME_CAPS)));
-
- clutter_keymap_update_state (CLUTTER_KEYMAP (keymap_native),
- caps_lock_state,
- num_lock_state,
- data->effective_layout_group,
- data->depressed_mods,
- data->latched_mods,
- data->locked_mods);
+ update_state_from_modifier_state (keymap_native, &data->modifier_state);
return G_SOURCE_REMOVE;
}
@@ -209,16 +237,7 @@ meta_keymap_native_update_in_impl (MetaKeymapNative *keymap_native,
data = g_new0 (UpdateLockedModifierStateData, 1);
data->keymap_native = keymap_native;
-
- data->depressed_mods =
- xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED);
- data->latched_mods =
- xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LATCHED);
- data->locked_mods =
- xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED);
-
- data->effective_layout_group =
- xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE);
+ data->modifier_state = calculate_modifier_state (xkb_state);
meta_seat_impl_queue_main_thread_idle (seat_impl,
update_state_in_main,
--
2.54.0
From 656d83e985b87b33cc77702502df3b1d65616116 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 21:21:38 +0200
Subject: [PATCH 14/32] backend: Make set_keymap API also take a layout index
This avoids always requiring a second call to a separate function to set
the layout index, where there is a short period of time where it's
potentially incorrect.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 50dd36fe3a2f46e43db618a420709dc6fc55373e)
---
clutter/clutter/clutter-keymap-private.h | 15 ++--
clutter/clutter/clutter-keymap.c | 12 ++--
src/backends/meta-backend-private.h | 1 +
src/backends/meta-backend.c | 2 +
src/backends/native/meta-backend-native.c | 2 +
.../native/meta-keymap-native-private.h | 3 +-
src/backends/native/meta-keymap-native.c | 35 +++++++---
src/backends/native/meta-seat-impl.c | 70 +++++++++++++++----
src/backends/native/meta-seat-impl.h | 1 +
src/backends/native/meta-seat-native.c | 10 ++-
src/backends/native/meta-seat-native.h | 1 +
src/compositor/plugins/default.c | 2 +-
src/meta/meta-backend.h | 1 +
src/tests/keyboard-map-tests.c | 6 +-
src/tests/remote-desktop-tests.c | 2 +-
15 files changed, 119 insertions(+), 44 deletions(-)
diff --git a/clutter/clutter/clutter-keymap-private.h b/clutter/clutter/clutter-keymap-private.h
index 047425c05e..5b65b880aa 100644
--- a/clutter/clutter/clutter-keymap-private.h
+++ b/clutter/clutter/clutter-keymap-private.h
@@ -21,10 +21,11 @@
#include "clutter/clutter-keymap.h"
CLUTTER_EXPORT
-void clutter_keymap_update_state (ClutterKeymap *keymap,
- gboolean caps_lock_state,
- gboolean num_lock_state,
- xkb_layout_index_t effective_layout_group,
- xkb_mod_mask_t depressed_mods,
- xkb_mod_mask_t latched_mods,
- xkb_mod_mask_t locked_mods);
+gboolean clutter_keymap_update_state (ClutterKeymap *keymap,
+ gboolean caps_lock_state,
+ gboolean num_lock_state,
+ xkb_layout_index_t effective_layout_group,
+ xkb_mod_mask_t depressed_mods,
+ xkb_mod_mask_t latched_mods,
+ xkb_mod_mask_t locked_mods,
+ gboolean emit_signal);
diff --git a/clutter/clutter/clutter-keymap.c b/clutter/clutter/clutter-keymap.c
index 8721990f74..4073da4f17 100644
--- a/clutter/clutter/clutter-keymap.c
+++ b/clutter/clutter/clutter-keymap.c
@@ -159,14 +159,15 @@ clutter_keymap_get_direction (ClutterKeymap *keymap)
return CLUTTER_KEYMAP_GET_CLASS (keymap)->get_direction (keymap);
}
-void
+gboolean
clutter_keymap_update_state (ClutterKeymap *keymap,
gboolean caps_lock_state,
gboolean num_lock_state,
xkb_layout_index_t effective_layout_group,
xkb_mod_mask_t depressed_mods,
xkb_mod_mask_t latched_mods,
- xkb_mod_mask_t locked_mods)
+ xkb_mod_mask_t locked_mods,
+ gboolean emit_signal)
{
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
@@ -176,7 +177,7 @@ clutter_keymap_update_state (ClutterKeymap *keymap,
priv->depressed_mods == depressed_mods &&
priv->latched_mods == latched_mods &&
priv->locked_mods == locked_mods)
- return;
+ return FALSE;
priv->effective_layout_group = effective_layout_group;
priv->depressed_mods = depressed_mods;
@@ -201,7 +202,10 @@ clutter_keymap_update_state (ClutterKeymap *keymap,
priv->num_lock_state ? "set" : "unset",
priv->caps_lock_state ? "set" : "unset");
- g_signal_emit (keymap, signals[STATE_CHANGED], 0);
+ if (emit_signal)
+ g_signal_emit (keymap, signals[STATE_CHANGED], 0);
+
+ return TRUE;
}
void
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index b7d92e6a4c..2cca4caa13 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -126,6 +126,7 @@ struct _MetaBackendClass
void (* set_keymap_async) (MetaBackend *backend,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GTask *task);
struct xkb_keymap * (* get_keymap) (MetaBackend *backend);
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 84e4d4cf25..926e94365b 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -1777,6 +1777,7 @@ meta_backend_set_keymap_finish (MetaBackend *backend,
void
meta_backend_set_keymap_async (MetaBackend *backend,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
@@ -1788,6 +1789,7 @@ meta_backend_set_keymap_async (MetaBackend *backend,
META_BACKEND_GET_CLASS (backend)->set_keymap_async (backend,
description,
+ layout_index,
task);
}
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 95dbfca41e..ebb95002a1 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -338,6 +338,7 @@ set_keyboard_map_cb (GObject *source_object,
static void
meta_backend_native_set_keymap_async (MetaBackend *backend,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GTask *task)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
@@ -346,6 +347,7 @@ meta_backend_native_set_keymap_async (MetaBackend *backend,
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_map_async (META_SEAT_NATIVE (seat),
description,
+ layout_index,
g_task_get_cancellable (task),
set_keyboard_map_cb,
task);
diff --git a/src/backends/native/meta-keymap-native-private.h b/src/backends/native/meta-keymap-native-private.h
index 2084393d5f..82d249eda8 100644
--- a/src/backends/native/meta-keymap-native-private.h
+++ b/src/backends/native/meta-keymap-native-private.h
@@ -28,7 +28,8 @@
void meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
MetaSeatImpl *seat_impl,
MetaKeymapDescription *keymap_description,
- struct xkb_keymap *xkb_keymap);
+ struct xkb_keymap *xkb_keymap,
+ struct xkb_state *xkb_state);
struct xkb_keymap * meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap);
diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c
index ec69950e0a..63f5b4cf29 100644
--- a/src/backends/native/meta-keymap-native.c
+++ b/src/backends/native/meta-keymap-native.c
@@ -129,9 +129,10 @@ calculate_modifier_state (struct xkb_state *xkb_state)
};
}
-static void
+static gboolean
update_state_from_modifier_state (MetaKeymapNative *keymap_native,
- ModifierState *modifier_state)
+ ModifierState *modifier_state,
+ gboolean emit_signal)
{
gboolean caps_lock_state;
gboolean num_lock_state;
@@ -145,13 +146,14 @@ update_state_from_modifier_state (MetaKeymapNative *keymap_native,
(1 << xkb_keymap_mod_get_index (keymap_native->impl.keymap,
XKB_MOD_NAME_CAPS)));
- clutter_keymap_update_state (CLUTTER_KEYMAP (keymap_native),
- caps_lock_state,
- num_lock_state,
- modifier_state->effective_layout_group,
- modifier_state->depressed_mods,
- modifier_state->latched_mods,
- modifier_state->locked_mods);
+ return clutter_keymap_update_state (CLUTTER_KEYMAP (keymap_native),
+ caps_lock_state,
+ num_lock_state,
+ modifier_state->effective_layout_group,
+ modifier_state->depressed_mods,
+ modifier_state->latched_mods,
+ modifier_state->locked_mods,
+ emit_signal);
}
typedef struct
@@ -159,6 +161,8 @@ typedef struct
MetaKeymapNative *keymap_native;
MetaKeymapDescription *keymap_description;
+
+ ModifierState modifier_state;
} UpdateKeymapData;
static void
@@ -175,9 +179,16 @@ update_keymap_in_main (gpointer user_data)
{
UpdateKeymapData *data = user_data;
MetaKeymapNative *keymap_native = data->keymap_native;
+ gboolean state_changed;
+
+ state_changed = update_state_from_modifier_state (keymap_native,
+ &data->modifier_state,
+ FALSE);
g_signal_emit (keymap_native, signals[KEYMAP_CHANGED], 0,
data->keymap_description);
+ if (state_changed)
+ g_signal_emit_by_name (keymap_native, "state-changed");
return G_SOURCE_REMOVE;
}
@@ -186,7 +197,8 @@ void
meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
MetaSeatImpl *seat_impl,
MetaKeymapDescription *keymap_description,
- struct xkb_keymap *xkb_keymap)
+ struct xkb_keymap *xkb_keymap,
+ struct xkb_state *xkb_state)
{
UpdateKeymapData *data;
@@ -197,6 +209,7 @@ meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
data = g_new0 (UpdateKeymapData, 1);
data->keymap_native = keymap;
+ data->modifier_state = calculate_modifier_state (xkb_state);
data->keymap_description = meta_keymap_description_ref (keymap_description);
meta_seat_impl_queue_main_thread_idle (seat_impl,
@@ -223,7 +236,7 @@ update_state_in_main (gpointer user_data)
UpdateLockedModifierStateData *data = user_data;
MetaKeymapNative *keymap_native = data->keymap_native;
- update_state_from_modifier_state (keymap_native, &data->modifier_state);
+ update_state_from_modifier_state (keymap_native, &data->modifier_state, TRUE);
return G_SOURCE_REMOVE;
}
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index 1a54cfe00c..f2ef0d8166 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3670,16 +3670,13 @@ meta_seat_impl_init (MetaSeatImpl *seat_impl)
seat_impl->barrier_manager = meta_barrier_manager_native_new ();
}
-void
-meta_seat_impl_update_xkb_state_in_impl (MetaSeatImpl *seat_impl)
+static void
+meta_seat_impl_update_xkb_state_in_impl_unlocked (MetaSeatImpl *seat_impl,
+ struct xkb_keymap *xkb_keymap,
+ xkb_layout_index_t layout_index)
{
xkb_mod_mask_t latched_mods = 0;
xkb_mod_mask_t locked_mods = 0;
- struct xkb_keymap *xkb_keymap;
-
- g_rw_lock_writer_lock (&seat_impl->state_lock);
-
- xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap);
if (seat_impl->xkb)
{
@@ -3696,15 +3693,29 @@ meta_seat_impl_update_xkb_state_in_impl (MetaSeatImpl *seat_impl)
0, /* depressed */
latched_mods,
locked_mods,
- 0, 0, seat_impl->layout_idx);
+ 0, 0, layout_index);
+
+ seat_impl->layout_idx = layout_index;
update_keyboard_leds (seat_impl);
meta_seat_impl_sync_leds_in_impl (seat_impl);
+}
+
+void
+meta_seat_impl_update_xkb_state_in_impl (MetaSeatImpl *seat_impl)
+{
+ struct xkb_keymap *xkb_keymap;
+
+ g_rw_lock_writer_lock (&seat_impl->state_lock);
+
+ xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap);
+ meta_seat_impl_update_xkb_state_in_impl_unlocked (seat_impl,
+ xkb_keymap,
+ seat_impl->layout_idx);
meta_keymap_native_update_in_impl (seat_impl->keymap,
seat_impl,
seat_impl->xkb);
-
g_rw_lock_writer_unlock (&seat_impl->state_lock);
}
@@ -3816,11 +3827,27 @@ meta_seat_impl_set_keyboard_map_finish (MetaSeatImpl *seat_impl,
return g_task_propagate_boolean (task, error);
}
+typedef struct
+{
+ MetaKeymapDescription *keymap_description;
+ xkb_layout_index_t layout_index;
+} SetKeymapData;
+
+static void
+set_keymap_data_free (gpointer user_data)
+{
+ SetKeymapData *data = user_data;
+
+ meta_keymap_description_unref (data->keymap_description);
+ g_free (data);
+}
+
static gboolean
set_keyboard_map (GTask *task)
{
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
- MetaKeymapDescription *keymap_description = g_task_get_task_data (task);
+ SetKeymapData *data = g_task_get_task_data (task);
+ MetaKeymapDescription *keymap_description = data->keymap_description;
MetaKeymapNative *keymap;
g_autoptr (GError) error = NULL;
struct xkb_keymap *xkb_keymap;
@@ -3838,12 +3865,21 @@ set_keyboard_map (GTask *task)
return G_SOURCE_REMOVE;
}
+ g_rw_lock_writer_lock (&seat_impl->state_lock);
+
+ meta_seat_impl_update_xkb_state_in_impl_unlocked (seat_impl,
+ xkb_keymap,
+ data->layout_index);
+
meta_keymap_native_set_keyboard_map_in_impl (keymap,
seat_impl,
keymap_description,
- xkb_keymap);
+ xkb_keymap,
+ seat_impl->xkb);
+ xkb_keymap_unref (xkb_keymap);
+
+ g_rw_lock_writer_unlock (&seat_impl->state_lock);
- meta_seat_impl_update_xkb_state_in_impl (seat_impl);
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
@@ -3865,20 +3901,24 @@ set_keyboard_map (GTask *task)
void
meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
MetaKeymapDescription *keymap_description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
+ SetKeymapData *data;
g_return_if_fail (META_IS_SEAT_IMPL (seat_impl));
g_return_if_fail (keymap_description);
task = g_task_new (seat_impl, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_seat_impl_set_keyboard_map_async);
- g_task_set_task_data (task,
- meta_keymap_description_ref (keymap_description),
- (GDestroyNotify) meta_keymap_description_unref);
+
+ data = g_new0 (SetKeymapData, 1);
+ data->keymap_description = meta_keymap_description_ref (keymap_description);
+ data->layout_index = layout_index;
+ g_task_set_task_data (task, data, set_keymap_data_free);
meta_seat_impl_run_input_task (seat_impl, task, (GSourceFunc) set_keyboard_map);
g_object_unref (task);
}
diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h
index 3637627a67..4950a19a74 100644
--- a/src/backends/native/meta-seat-impl.h
+++ b/src/backends/native/meta-seat-impl.h
@@ -191,6 +191,7 @@ gboolean meta_seat_impl_set_keyboard_map_finish (MetaSeatImpl *seat_impl,
void meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
MetaKeymapDescription *keymap_description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 9be0bd7ce1..921cdb2fc6 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -68,6 +68,7 @@ G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT)
static gboolean meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GError **error);
@@ -186,6 +187,8 @@ on_keymap_changed (MetaKeymapNative *keymap_native,
g_clear_pointer (&seat_native->xkb_keymap, xkb_keymap_unref);
seat_native->xkb_keymap = xkb_keymap;
+ seat_native->xkb_layout_index =
+ clutter_keymap_get_layout_index (CLUTTER_KEYMAP (keymap_native));
g_signal_emit (seat_native, signals[KEYMAP_CHANGED], 0);
}
@@ -221,7 +224,7 @@ meta_seat_native_constructed (GObject *object)
NULL,
NULL);
if (!meta_seat_native_set_keyboard_map_sync (seat,
- keymap_description,
+ keymap_description, 0,
NULL, &error))
g_warning ("Failed to set keyboard map: %s", error->message);
@@ -612,6 +615,7 @@ set_impl_keyboard_map_cb (GObject *source_object,
void
meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
@@ -623,6 +627,7 @@ meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
meta_seat_impl_set_keyboard_map_async (seat->impl,
description,
+ layout_index,
cancellable,
set_impl_keyboard_map_cb,
g_object_ref (task));
@@ -652,6 +657,7 @@ sync_set_impl_keyboard_map_cb (GObject *source_object,
static gboolean
meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GError **error)
{
@@ -669,6 +675,7 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
meta_seat_impl_set_keyboard_map_async (seat_native->impl,
description,
+ layout_index,
cancellable,
sync_set_impl_keyboard_map_cb,
task);
@@ -686,6 +693,7 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
g_clear_pointer (&seat_native->xkb_keymap, xkb_keymap_unref);
seat_native->xkb_keymap = xkb_keymap_ref (xkb_keymap);
+ seat_native->xkb_layout_index = layout_index;
g_clear_pointer (&seat_native->keymap_description,
meta_keymap_description_unref);
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index fc0663086e..2799d895d2 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -103,6 +103,7 @@ void meta_seat_native_reclaim_devices (MetaSeatNative *seat);
void meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c
index 094cec07ea..3ce1e491e1 100644
--- a/src/compositor/plugins/default.c
+++ b/src/compositor/plugins/default.c
@@ -421,7 +421,7 @@ init_keymap (MetaDefaultPlugin *self,
x11_options);
meta_backend_set_keymap_async (backend,
- keymap_description,
+ keymap_description, 0,
NULL, NULL, NULL);
}
diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h
index 74ad2bfebf..cd93fc9a72 100644
--- a/src/meta/meta-backend.h
+++ b/src/meta/meta-backend.h
@@ -51,6 +51,7 @@ gboolean meta_backend_set_keymap_finish (MetaBackend *backend,
META_EXPORT
void meta_backend_set_keymap_async (MetaBackend *backend,
MetaKeymapDescription *description,
+ uint32_t layout_index,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index 8d93dababf..c307c80e83 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -161,7 +161,7 @@ meta_test_native_keyboard_map_set_async (void)
"us",
"dvorak-alt-intl",
NULL);
- meta_backend_set_keymap_async (backend, keymap_description,
+ meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
g_assert_true (xkb_keymap == meta_backend_get_keymap (backend));
@@ -210,7 +210,7 @@ meta_test_native_keyboard_map_change_layout (void)
"us,ua",
NULL,
"grp:caps_select");
- meta_backend_set_keymap_async (backend, keymap_description,
+ meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
while (!done)
@@ -292,7 +292,7 @@ meta_test_native_keyboard_map_set_layout_index (void)
"us,se",
"dvorak-alt-intl,svdvorak",
NULL);
- meta_backend_set_keymap_async (backend, keymap_description,
+ meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
diff --git a/src/tests/remote-desktop-tests.c b/src/tests/remote-desktop-tests.c
index a2ce8ce388..75266a0838 100644
--- a/src/tests/remote-desktop-tests.c
+++ b/src/tests/remote-desktop-tests.c
@@ -77,7 +77,7 @@ remote_desktop_test_client_command (int argc,
layout,
variant,
NULL);
- meta_backend_set_keymap_async (backend, keymap_description,
+ meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
--
2.54.0
From c258b53959ba34625f2fb5913f87dc9bba23a7cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 21:35:05 +0200
Subject: [PATCH 15/32] Add 'sealed fd' type
Copied from xdg-desktop-portal, with some unused API skipped. Will be
used to wrap sealed memfd file descriptors, with a convenient API to
retrieve the actual data.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 7225cec4ced3bd57614800bc8a938c114a226cad)
---
src/core/meta-sealed-fd.c | 175 ++++++++++++++++++++++++++++++++++++++
src/core/meta-sealed-fd.h | 43 ++++++++++
src/meson.build | 2 +
3 files changed, 220 insertions(+)
create mode 100644 src/core/meta-sealed-fd.c
create mode 100644 src/core/meta-sealed-fd.h
diff --git a/src/core/meta-sealed-fd.c b/src/core/meta-sealed-fd.c
new file mode 100644
index 0000000000..57172104a5
--- /dev/null
+++ b/src/core/meta-sealed-fd.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2024 GNOME Foundation Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Julian Sparber <jsparber@gnome.org>
+ */
+
+#include "config.h"
+
+#include "core/meta-sealed-fd.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <gio/gunixfdlist.h>
+#include <glib/gstdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#define REQUIRED_SEALS (F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SHRINK)
+
+struct _MetaSealedFd
+{
+ GObject parent_instance;
+
+ int fd;
+};
+
+G_DEFINE_FINAL_TYPE (MetaSealedFd, meta_sealed_fd, G_TYPE_OBJECT)
+
+static void
+meta_sealed_fd_finalize (GObject *object)
+{
+ MetaSealedFd *sealed_fd = META_SEALED_FD (object);
+ g_autoptr (GError) error = NULL;
+
+ if (!g_clear_fd (&sealed_fd->fd, &error))
+ g_warning ("Error closing sealed fd: %s", error->message);
+
+ G_OBJECT_CLASS (meta_sealed_fd_parent_class)->finalize (object);
+}
+
+static void
+meta_sealed_fd_class_init (MetaSealedFdClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meta_sealed_fd_finalize;
+}
+
+static void
+meta_sealed_fd_init (MetaSealedFd *sealed_fd)
+{
+ sealed_fd->fd = -1;
+}
+
+MetaSealedFd *
+meta_sealed_fd_new_take_memfd (int memfd,
+ GError **error)
+{
+ g_autoptr (MetaSealedFd) sealed_fd = NULL;
+ g_autofd int fd = g_steal_fd (&memfd);
+ int saved_errno = -1;
+ int seals;
+
+ g_return_val_if_fail (fd != -1, NULL);
+
+ seals = fcntl (fd, F_GET_SEALS);
+ if (seals == -1)
+ {
+ saved_errno = errno;
+
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (saved_errno),
+ "fcntl F_GET_SEALS: %s", g_strerror (saved_errno));
+ return NULL;
+ }
+
+ /* If the seal seal is set and some required seal is missing report EPERM error directly */
+ if ((seals & F_SEAL_SEAL) && (seals & REQUIRED_SEALS) != REQUIRED_SEALS)
+ saved_errno = EPERM;
+ else if (fcntl (fd, F_ADD_SEALS, REQUIRED_SEALS) == -1)
+ saved_errno = errno;
+
+ if (saved_errno != -1)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (saved_errno),
+ "fcntl F_ADD_SEALS: %s", g_strerror (saved_errno));
+ return NULL;
+ }
+
+ sealed_fd = g_object_new (META_TYPE_SEALED_FD, NULL);
+ sealed_fd->fd = g_steal_fd (&fd);
+
+ return g_steal_pointer (&sealed_fd);
+}
+
+MetaSealedFd *
+meta_sealed_fd_new_from_handle (GVariant *handle,
+ GUnixFDList *fd_list,
+ GError **error)
+{
+ g_autofd int fd = -1;
+ int fd_id;
+
+ if (!g_variant_is_of_type (handle, G_VARIANT_TYPE_HANDLE))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "GVariant is not a file descriptor handle");
+ return NULL;
+ }
+
+ if (!fd_list)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Invalid file descriptor: index not found (empty list)");
+ return NULL;
+ }
+
+ fd_id = g_variant_get_handle (handle);
+ if (fd_id >= g_unix_fd_list_get_length (fd_list))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Invalid file descriptor: index not found");
+ return NULL;
+ }
+
+ fd = g_unix_fd_list_get (fd_list, fd_id, error);
+ if (fd == -1)
+ return NULL;
+
+ return meta_sealed_fd_new_take_memfd (g_steal_fd (&fd), error);
+}
+
+int
+meta_sealed_fd_get_fd (MetaSealedFd *sealed_fd)
+{
+ g_return_val_if_fail (META_IS_SEALED_FD (sealed_fd), -1);
+
+ return sealed_fd->fd;
+}
+
+int
+meta_sealed_fd_dup_fd (MetaSealedFd *sealed_fd)
+{
+ g_return_val_if_fail (META_IS_SEALED_FD (sealed_fd), -1);
+
+ return dup (sealed_fd->fd);
+}
+
+GBytes *
+meta_sealed_fd_get_bytes (MetaSealedFd *sealed_fd,
+ GError **error)
+{
+ g_autoptr (GMappedFile) mapped = NULL;
+
+ mapped = g_mapped_file_new_from_fd (sealed_fd->fd, FALSE, error);
+ return g_mapped_file_get_bytes (mapped);
+}
diff --git a/src/core/meta-sealed-fd.h b/src/core/meta-sealed-fd.h
new file mode 100644
index 0000000000..2721fdddb9
--- /dev/null
+++ b/src/core/meta-sealed-fd.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2024 GNOME Foundation Inc.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#define META_TYPE_SEALED_FD (meta_sealed_fd_get_type())
+G_DECLARE_FINAL_TYPE (MetaSealedFd,
+ meta_sealed_fd,
+ META, SEALED_FD,
+ GObject)
+
+MetaSealedFd * meta_sealed_fd_new_take_memfd (int memfd,
+ GError **error);
+
+MetaSealedFd * meta_sealed_fd_new_from_handle (GVariant *handle,
+ GUnixFDList *fd_list,
+ GError **error);
+
+int meta_sealed_fd_get_fd (MetaSealedFd *sealed_fd);
+
+int meta_sealed_fd_dup_fd (MetaSealedFd *sealed_fd);
+
+GBytes *meta_sealed_fd_get_bytes (MetaSealedFd *sealed_fd,
+ GError **error);
diff --git a/src/meson.build b/src/meson.build
index e7824f502e..59e8f079c2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -373,6 +373,8 @@ mutter_sources = [
'core/meta-launch-context.c',
'core/meta-pad-action-mapper.c',
'core/meta-private-enums.h',
+ 'core/meta-sealed-fd.c',
+ 'core/meta-sealed-fd.h',
'core/meta-selection.c',
'core/meta-selection-source.c',
'core/meta-selection-source-memory.c',
--
2.54.0
From ab6003a40aa34f95fe8f10ea2e956638163938f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 21:41:23 +0200
Subject: [PATCH 16/32] keymap-description: Add way to create keymap
description from fd
This will be used to set the actual keyboard layout from a sealed memfd
file descriptor via the remote desktop D-Bus API.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit fcd93d433dddbb79dcc01682d2626e5c47dc9eaf)
---
.../meta-keymap-description-private.h | 13 ++
src/backends/meta-keymap-description.c | 169 +++++++++++++-----
2 files changed, 137 insertions(+), 45 deletions(-)
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index 3cacfe6561..6504371a6c 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -20,5 +20,18 @@
#include "meta/meta-keymap-description.h"
+#include "core/meta-sealed-fd.h"
+
+typedef enum _MetaKeymapDescriptionSource
+{
+ META_KEYMAP_DESCRIPTION_SOURCE_RULES,
+ META_KEYMAP_DESCRIPTION_SOURCE_FD,
+} MetaKeymapDescriptionSource;
+
+MetaKeymapDescription * meta_keymap_description_new_from_fd (MetaSealedFd *sealed_fd,
+ enum xkb_keymap_format format);
+
+MetaKeymapDescriptionSource meta_keymap_description_get_source (MetaKeymapDescription *keymap_description);
+
struct xkb_keymap * meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
GError **error);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index cd93c543e3..77d372824e 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -21,18 +21,30 @@
#include "backends/meta-keymap-description-private.h"
#include <glib-object.h>
+#include <xkbcommon/xkbregistry.h>
#include "backends/meta-keymap-utils.h"
+#include "core/meta-sealed-fd.h"
struct _MetaKeymapDescription
{
gatomicrefcount ref_count;
- char *rules;
- char *model;
- char *layout;
- char *variant;
- char *options;
+ MetaKeymapDescriptionSource source;
+
+ union {
+ struct {
+ char *rules;
+ char *model;
+ char *layout;
+ char *variant;
+ char *options;
+ } rules;
+ struct {
+ MetaSealedFd *sealed_fd;
+ enum xkb_keymap_format format;
+ } fd;
+ };
};
#define DEFAULT_XKB_RULES_FILE "evdev"
@@ -58,11 +70,27 @@ meta_keymap_description_new_from_rules (const char *model,
keymap_description = g_new0 (MetaKeymapDescription, 1);
g_atomic_ref_count_init (&keymap_description->ref_count);
- keymap_description->model = model ? g_strdup (model)
- : g_strdup (DEFAULT_XKB_MODEL);
- keymap_description->layout = strdup_or_empty (layout);
- keymap_description->variant = strdup_or_empty (variant);
- keymap_description->options = strdup_or_empty (options);
+ keymap_description->source = META_KEYMAP_DESCRIPTION_SOURCE_RULES;
+ keymap_description->rules.model = model ? g_strdup (model)
+ : g_strdup (DEFAULT_XKB_MODEL);
+ keymap_description->rules.layout = strdup_or_empty (layout);
+ keymap_description->rules.variant = strdup_or_empty (variant);
+ keymap_description->rules.options = strdup_or_empty (options);
+
+ return keymap_description;
+}
+
+MetaKeymapDescription *
+meta_keymap_description_new_from_fd (MetaSealedFd *sealed_fd,
+ enum xkb_keymap_format format)
+{
+ MetaKeymapDescription *keymap_description;
+
+ keymap_description = g_new0 (MetaKeymapDescription, 1);
+ g_atomic_ref_count_init (&keymap_description->ref_count);
+ keymap_description->source = META_KEYMAP_DESCRIPTION_SOURCE_FD;
+ g_set_object (&keymap_description->fd.sealed_fd, sealed_fd);
+ keymap_description->fd.format = format;
return keymap_description;
}
@@ -79,47 +107,98 @@ meta_keymap_description_unref (MetaKeymapDescription *keymap_description)
{
if (g_atomic_ref_count_dec (&keymap_description->ref_count))
{
- g_free (keymap_description->model);
- g_free (keymap_description->layout);
- g_free (keymap_description->variant);
- g_free (keymap_description->options);
+ switch (keymap_description->source)
+ {
+ case META_KEYMAP_DESCRIPTION_SOURCE_RULES:
+ g_free (keymap_description->rules.model);
+ g_free (keymap_description->rules.layout);
+ g_free (keymap_description->rules.variant);
+ g_free (keymap_description->rules.options);
+ break;
+ case META_KEYMAP_DESCRIPTION_SOURCE_FD:
+ g_clear_object (&keymap_description->fd.sealed_fd);
+ break;
+ }
+
g_free (keymap_description);
}
}
+MetaKeymapDescriptionSource
+meta_keymap_description_get_source (MetaKeymapDescription *keymap_description)
+{
+ return keymap_description->source;
+}
+
struct xkb_keymap *
meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
GError **error)
{
- struct xkb_rule_names names;
- struct xkb_context *xkb_context;
- struct xkb_keymap *xkb_keymap;
-
- names.rules = DEFAULT_XKB_RULES_FILE;
- names.model = keymap_description->model;
- names.layout = keymap_description->layout;
- names.variant = keymap_description->variant;
- names.options = keymap_description->options;
-
- xkb_context = meta_create_xkb_context ();
- xkb_keymap = xkb_keymap_new_from_names (xkb_context,
- &names,
- XKB_KEYMAP_COMPILE_NO_FLAGS);
- xkb_context_unref (xkb_context);
-
- if (!xkb_keymap)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Failed to create XKB keymap with "
- "rules=%s, model=%s, layout=%s, "
- "variant=%s, options=%s",
- keymap_description->rules,
- keymap_description->model,
- keymap_description->layout,
- keymap_description->variant,
- keymap_description->options);
- return NULL;
- }
-
- return xkb_keymap;
+ switch (keymap_description->source)
+ {
+ case META_KEYMAP_DESCRIPTION_SOURCE_RULES:
+ {
+ struct xkb_rule_names names;
+ struct xkb_context *xkb_context;
+ struct xkb_keymap *xkb_keymap;
+
+ names.rules = DEFAULT_XKB_RULES_FILE;
+ names.model = keymap_description->rules.model;
+ names.layout = keymap_description->rules.layout;
+ names.variant = keymap_description->rules.variant;
+ names.options = keymap_description->rules.options;
+
+ xkb_context = meta_create_xkb_context ();
+ xkb_keymap = xkb_keymap_new_from_names (xkb_context,
+ &names,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_context_unref (xkb_context);
+
+ if (!xkb_keymap)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to create XKB keymap with "
+ "rules=%s, model=%s, layout=%s, "
+ "variant=%s, options=%s",
+ keymap_description->rules.rules,
+ keymap_description->rules.model,
+ keymap_description->rules.layout,
+ keymap_description->rules.variant,
+ keymap_description->rules.options);
+ return NULL;
+ }
+
+ return xkb_keymap;
+ }
+ case META_KEYMAP_DESCRIPTION_SOURCE_FD:
+ {
+ g_autoptr (GBytes) keymap_bytes = NULL;
+ struct xkb_context *xkb_context;
+ struct xkb_keymap *xkb_keymap;
+
+ keymap_bytes =
+ meta_sealed_fd_get_bytes (keymap_description->fd.sealed_fd, error);
+ if (!keymap_bytes)
+ return NULL;
+
+ xkb_context = meta_create_xkb_context ();
+ xkb_keymap =
+ xkb_keymap_new_from_string (xkb_context,
+ g_bytes_get_data (keymap_bytes, NULL),
+ keymap_description->fd.format,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_context_unref (xkb_context);
+
+ if (!xkb_keymap)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to create XKB keymap from file descriptor");
+ return NULL;
+ }
+
+ return xkb_keymap;
+ }
+ }
+
+ g_assert_not_reached ();
}
--
2.54.0
From 3e13d05b82513d03a990b8fbb2a146b0d234f7d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 10:09:25 +0200
Subject: [PATCH 17/32] backend: Add API to get current keymap description
This will be used to retrieve information related to the current keymap,
but not part of the keymap itself. Currently there are no such
information, but it will be added in the future.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit f2b1c0e8d1bd867f9b62ac0fff5c5a03dd4381df)
---
src/backends/meta-backend-private.h | 2 ++
src/backends/meta-backend.c | 15 +++++++++++++++
src/backends/native/meta-backend-native.c | 11 +++++++++++
src/backends/native/meta-seat-native.c | 9 +++++++++
src/backends/native/meta-seat-native.h | 2 ++
src/meta/meta-backend.h | 3 +++
6 files changed, 42 insertions(+)
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 2cca4caa13..dccd1116a6 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -131,6 +131,8 @@ struct _MetaBackendClass
struct xkb_keymap * (* get_keymap) (MetaBackend *backend);
+ MetaKeymapDescription * (* get_keymap_description) (MetaBackend *backend);
+
xkb_layout_index_t (* get_keymap_layout_group) (MetaBackend *backend);
void (* set_keymap_layout_group_async) (MetaBackend *backend,
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 926e94365b..beaec1f281 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -1799,6 +1799,21 @@ meta_backend_get_keymap (MetaBackend *backend)
return META_BACKEND_GET_CLASS (backend)->get_keymap (backend);
}
+/**
+ * meta_backend_get_keymap_description:
+ * @backend: a #MetaBackend
+ * keyboard map description
+ *
+ * Gets the description of the current keyboard map.
+ *
+ * Returns: (transfer none): The current keymap description.
+ */
+MetaKeymapDescription *
+meta_backend_get_keymap_description (MetaBackend *backend)
+{
+ return META_BACKEND_GET_CLASS (backend)->get_keymap_description (backend);
+}
+
xkb_layout_index_t
meta_backend_get_keymap_layout_group (MetaBackend *backend)
{
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index ebb95002a1..b2efac59d1 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -364,6 +364,16 @@ meta_backend_native_get_keymap (MetaBackend *backend)
return meta_seat_native_get_keyboard_map (META_SEAT_NATIVE (seat));
}
+static MetaKeymapDescription *
+meta_backend_native_get_keymap_description (MetaBackend *backend)
+{
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ ClutterSeat *seat;
+
+ seat = clutter_backend_get_default_seat (clutter_backend);
+ return meta_seat_native_get_keyboard_map_description (META_SEAT_NATIVE (seat));
+}
+
static xkb_layout_index_t
meta_backend_native_get_keymap_layout_group (MetaBackend *backend)
{
@@ -942,6 +952,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
backend_class->set_keymap_async = meta_backend_native_set_keymap_async;
backend_class->get_keymap = meta_backend_native_get_keymap;
+ backend_class->get_keymap_description = meta_backend_native_get_keymap_description;
backend_class->get_keymap_layout_group = meta_backend_native_get_keymap_layout_group;
backend_class->set_keymap_layout_group_async = meta_backend_native_set_keymap_layout_group_async;
backend_class->update_stage = meta_backend_native_update_stage;
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 921cdb2fc6..fc849044f9 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -295,6 +295,7 @@ meta_seat_native_dispose (GObject *object)
g_clear_object (&seat->core_pointer);
g_clear_object (&seat->core_keyboard);
g_clear_pointer (&seat->impl, meta_seat_impl_destroy);
+ g_clear_pointer (&seat->keymap_description, meta_keymap_description_unref);
g_list_free_full (g_steal_pointer (&seat->devices), g_object_unref);
g_clear_pointer (&seat->reserved_virtual_slots, g_hash_table_destroy);
g_clear_pointer (&seat->tablet_cursors, g_hash_table_unref);
@@ -718,6 +719,14 @@ meta_seat_native_get_keyboard_map (MetaSeatNative *seat)
return seat->xkb_keymap;
}
+MetaKeymapDescription *
+meta_seat_native_get_keyboard_map_description (MetaSeatNative *seat_native)
+{
+ g_return_val_if_fail (seat_native->keymap_description, NULL);
+
+ return seat_native->keymap_description;
+}
+
gboolean
meta_seat_native_set_keyboard_layout_index_finish (MetaSeatNative *seat_native,
GAsyncResult *result,
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index 2799d895d2..061b580bc2 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -125,6 +125,8 @@ void meta_seat_native_set_keyboard_layout_index_async (MetaSeatNative *seat
GAsyncReadyCallback callback,
gpointer user_data);
+MetaKeymapDescription * meta_seat_native_get_keyboard_map_description (MetaSeatNative *seat_native);
+
xkb_layout_index_t meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat);
void meta_seat_native_set_keyboard_repeat (MetaSeatNative *seat,
diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h
index cd93fc9a72..63dde15575 100644
--- a/src/meta/meta-backend.h
+++ b/src/meta/meta-backend.h
@@ -56,6 +56,9 @@ void meta_backend_set_keymap_async (MetaBackend *backend,
GAsyncReadyCallback callback,
gpointer user_data);
+META_EXPORT
+MetaKeymapDescription * meta_backend_get_keymap_description (MetaBackend *backend);
+
META_EXPORT
gboolean meta_backend_set_keymap_layout_group_finish (MetaBackend *backend,
GAsyncResult *result,
--
2.54.0
From 7f512c1d8a6e3222d79756852a20c0d161d145cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 10:30:16 +0200
Subject: [PATCH 18/32] keymap-description: Provide descriptive names together
with xkb_keymap
These descriptive names are meant to e.g. show in the GNOME Shell input
source indicator if the keymap is set from something other than GNOME
Shell itself.
Both the short and long names are optional, e.g. not needed by the
default shell, which doesn't show the current layout, however, will fall
back on the name from the xkb_keymap itself if not specified.
For rules based keymaps, the one creating said keymap can specify both
the display name and short name, and for the descriptions created for
serialized keymaps derive them by searching for the short name in the
XKB registry given the display name.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit f74b640c6ae69338affcc23d9061f8ee73d6fe71)
---
meson.build | 1 +
.../meta-keymap-description-private.h | 2 +
src/backends/meta-keymap-description.c | 103 +++++++++++++++++-
src/backends/native/meta-seat-impl.c | 2 +
src/backends/native/meta-seat-native.c | 4 +
src/compositor/plugins/default.c | 3 +-
src/core/keybindings.c | 3 +
src/meson.build | 1 +
src/meta/meta-keymap-description.h | 4 +-
src/tests/keyboard-map-tests.c | 8 +-
src/tests/remote-desktop-tests.c | 2 +
11 files changed, 124 insertions(+), 9 deletions(-)
diff --git a/meson.build b/meson.build
index f77badb9ae..f508db69ec 100644
--- a/meson.build
+++ b/meson.build
@@ -131,6 +131,7 @@ libadwaita_dep = dependency('libadwaita-1', required: false)
gmodule_no_export_dep = dependency('gmodule-no-export-2.0', version: glib_req)
gnome_settings_daemon_dep = dependency('gnome-settings-daemon', required: false)
xkbcommon_dep = dependency('xkbcommon', version: xkbcommon_req)
+xkbregistry_dep = dependency('xkbregistry')
atk_dep = dependency('atk', version: atk_req)
colord_dep = dependency('colord', version: colord_req)
lcms2_dep = dependency('lcms2', version: lcms2_req)
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index 6504371a6c..3c0d9cc924 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -34,4 +34,6 @@ MetaKeymapDescription * meta_keymap_description_new_from_fd (MetaSealedFd
MetaKeymapDescriptionSource meta_keymap_description_get_source (MetaKeymapDescription *keymap_description);
struct xkb_keymap * meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
+ GStrv *out_display_names,
+ GStrv *out_short_names,
GError **error);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index 77d372824e..63bd539d57 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -39,6 +39,8 @@ struct _MetaKeymapDescription
char *layout;
char *variant;
char *options;
+ GStrv display_names;
+ GStrv short_names;
} rules;
struct {
MetaSealedFd *sealed_fd;
@@ -64,7 +66,9 @@ MetaKeymapDescription *
meta_keymap_description_new_from_rules (const char *model,
const char *layout,
const char *variant,
- const char *options)
+ const char *options,
+ GStrv display_names,
+ GStrv short_names)
{
MetaKeymapDescription *keymap_description;
@@ -76,6 +80,8 @@ meta_keymap_description_new_from_rules (const char *model,
keymap_description->rules.layout = strdup_or_empty (layout);
keymap_description->rules.variant = strdup_or_empty (variant);
keymap_description->rules.options = strdup_or_empty (options);
+ keymap_description->rules.display_names = g_strdupv (display_names);
+ keymap_description->rules.short_names = g_strdupv (short_names);
return keymap_description;
}
@@ -114,6 +120,8 @@ meta_keymap_description_unref (MetaKeymapDescription *keymap_description)
g_free (keymap_description->rules.layout);
g_free (keymap_description->rules.variant);
g_free (keymap_description->rules.options);
+ g_strfreev (keymap_description->rules.display_names);
+ g_strfreev (keymap_description->rules.short_names);
break;
case META_KEYMAP_DESCRIPTION_SOURCE_FD:
g_clear_object (&keymap_description->fd.sealed_fd);
@@ -130,17 +138,42 @@ meta_keymap_description_get_source (MetaKeymapDescription *keymap_description)
return keymap_description->source;
}
+static char *
+maybe_derive_short_name (struct rxkb_context *rxkb_context,
+ const char *layout_name)
+{
+ struct rxkb_layout *rxkb_layout;
+ if (!layout_name)
+ return NULL;
+
+ for (rxkb_layout = rxkb_layout_first (rxkb_context);
+ rxkb_layout;
+ rxkb_layout = rxkb_layout_next (rxkb_layout))
+ {
+ if (g_strcmp0 (layout_name,
+ rxkb_layout_get_description (rxkb_layout)) == 0)
+ return g_strdup (rxkb_layout_get_brief (rxkb_layout));
+ }
+
+ return NULL;
+}
+
struct xkb_keymap *
meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_description,
+ GStrv *out_display_names,
+ GStrv *out_short_names,
GError **error)
{
+ g_auto (GStrv) display_names = NULL;
+ g_auto (GStrv) short_names = NULL;
+ struct xkb_keymap *xkb_keymap = NULL;
+
switch (keymap_description->source)
{
case META_KEYMAP_DESCRIPTION_SOURCE_RULES:
{
struct xkb_rule_names names;
struct xkb_context *xkb_context;
- struct xkb_keymap *xkb_keymap;
names.rules = DEFAULT_XKB_RULES_FILE;
names.model = keymap_description->rules.model;
@@ -168,13 +201,17 @@ meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_descri
return NULL;
}
- return xkb_keymap;
+ if (out_display_names)
+ display_names = g_strdupv (keymap_description->rules.display_names);
+ if (out_short_names)
+ short_names = g_strdupv (keymap_description->rules.short_names);
+
+ break;
}
case META_KEYMAP_DESCRIPTION_SOURCE_FD:
{
g_autoptr (GBytes) keymap_bytes = NULL;
struct xkb_context *xkb_context;
- struct xkb_keymap *xkb_keymap;
keymap_bytes =
meta_sealed_fd_get_bytes (keymap_description->fd.sealed_fd, error);
@@ -196,9 +233,63 @@ meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_descri
return NULL;
}
- return xkb_keymap;
+ break;
}
}
- g_assert_not_reached ();
+ g_assert (xkb_keymap);
+
+ if (out_display_names && !display_names)
+ {
+ g_autoptr (GStrvBuilder) display_names_builder = NULL;
+ xkb_layout_index_t n_layouts, i;
+
+ display_names_builder = g_strv_builder_new ();
+ n_layouts = xkb_keymap_num_layouts (xkb_keymap);
+ for (i = 0; i < n_layouts; i++)
+ {
+ const char *display_name;
+
+ display_name = xkb_keymap_layout_get_name (xkb_keymap, i);
+ g_strv_builder_add (display_names_builder,
+ display_name ? display_name : "");
+ }
+
+ display_names = g_strv_builder_end (display_names_builder);
+ }
+
+ if (out_short_names && !short_names)
+ {
+ g_autoptr (GStrvBuilder) short_names_builder = NULL;
+ struct rxkb_context *rxkb_context = NULL;
+
+ short_names_builder = g_strv_builder_new ();
+
+ rxkb_context = rxkb_context_new (RXKB_CONTEXT_LOAD_EXOTIC_RULES);
+ if (rxkb_context_parse (rxkb_context, "evdev"))
+ {
+ xkb_layout_index_t n_layouts, i;
+
+ n_layouts = xkb_keymap_num_layouts (xkb_keymap);
+ for (i = 0; i < n_layouts; i++)
+ {
+ g_autofree char *short_name = NULL;
+
+ short_name = maybe_derive_short_name (rxkb_context,
+ display_names[i]);
+ g_strv_builder_add (short_names_builder,
+ short_name ? short_name : "");
+ }
+
+ short_names = g_strv_builder_end (short_names_builder);
+ }
+ rxkb_context_unref (rxkb_context);
+ }
+
+ if (out_display_names)
+ *out_display_names = g_steal_pointer (&display_names);
+ if (out_short_names)
+ *out_short_names = g_steal_pointer (&short_names);
+
+ return xkb_keymap;
}
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index f2ef0d8166..a5d490d12b 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3857,6 +3857,8 @@ set_keyboard_map (GTask *task)
keymap = seat_impl->keymap;
xkb_keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
+ NULL,
+ NULL,
&error);
if (!xkb_keymap)
{
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index fc849044f9..5498bac13f 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -173,6 +173,7 @@ on_keymap_changed (MetaKeymapNative *keymap_native,
xkb_keymap =
meta_keymap_description_create_xkb_keymap (keymap_description,
+ NULL, NULL,
&error);
if (!xkb_keymap)
{
@@ -222,6 +223,8 @@ meta_seat_native_constructed (GObject *object)
keymap_description = meta_keymap_description_new_from_rules (NULL,
"us",
NULL,
+ NULL,
+ NULL,
NULL);
if (!meta_seat_native_set_keyboard_map_sync (seat,
keymap_description, 0,
@@ -688,6 +691,7 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
xkb_keymap =
meta_keymap_description_create_xkb_keymap (description,
+ NULL, NULL,
error);
if (!xkb_keymap)
return FALSE;
diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c
index 3ce1e491e1..cbce7ab959 100644
--- a/src/compositor/plugins/default.c
+++ b/src/compositor/plugins/default.c
@@ -418,7 +418,8 @@ init_keymap (MetaDefaultPlugin *self,
keymap_description = meta_keymap_description_new_from_rules (x11_model,
x11_layout,
x11_variant,
- x11_options);
+ x11_options,
+ NULL, NULL);
meta_backend_set_keymap_async (backend,
keymap_description, 0,
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 0f475eae3b..6f879eed8e 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -773,8 +773,11 @@ create_us_layout (void)
keymap_description = meta_keymap_description_new_from_rules (NULL,
"us",
NULL,
+ NULL,
+ NULL,
NULL);
keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
+ NULL, NULL,
&error);
if (!keymap)
{
diff --git a/src/meson.build b/src/meson.build
index 59e8f079c2..72b70e3199 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -26,6 +26,7 @@ mutter_pkg_private_deps = [
gnome_settings_daemon_dep,
xkbcommon_dep,
gdk_pixbuf_dep,
+ xkbregistry_dep,
libeis_dep,
libdisplay_info_dep,
]
diff --git a/src/meta/meta-keymap-description.h b/src/meta/meta-keymap-description.h
index 32e9ef6d2d..5140f63b1a 100644
--- a/src/meta/meta-keymap-description.h
+++ b/src/meta/meta-keymap-description.h
@@ -32,7 +32,9 @@ META_EXPORT
MetaKeymapDescription * meta_keymap_description_new_from_rules (const char *model,
const char *layout,
const char *variant,
- const char *options);
+ const char *options,
+ GStrv display_names,
+ GStrv short_names);
META_EXPORT
MetaKeymapDescription * meta_keymap_description_ref (MetaKeymapDescription *keymap_description);
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index c307c80e83..e1a65214cc 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -160,6 +160,8 @@ meta_test_native_keyboard_map_set_async (void)
meta_keymap_description_new_from_rules (NULL,
"us",
"dvorak-alt-intl",
+ NULL,
+ NULL,
NULL);
meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
@@ -209,7 +211,9 @@ meta_test_native_keyboard_map_change_layout (void)
meta_keymap_description_new_from_rules (NULL,
"us,ua",
NULL,
- "grp:caps_select");
+ "grp:caps_select",
+ NULL,
+ NULL);
meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
@@ -291,6 +295,8 @@ meta_test_native_keyboard_map_set_layout_index (void)
meta_keymap_description_new_from_rules (NULL,
"us,se",
"dvorak-alt-intl,svdvorak",
+ NULL,
+ NULL,
NULL);
meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
diff --git a/src/tests/remote-desktop-tests.c b/src/tests/remote-desktop-tests.c
index 75266a0838..9ebc320bd0 100644
--- a/src/tests/remote-desktop-tests.c
+++ b/src/tests/remote-desktop-tests.c
@@ -76,6 +76,8 @@ remote_desktop_test_client_command (int argc,
keymap_description = meta_keymap_description_new_from_rules (NULL,
layout,
variant,
+ NULL,
+ NULL,
NULL);
meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
--
2.54.0
From c01134a4584fad21873333bdbabf06439da9050e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 1 Oct 2025 15:14:40 +0200
Subject: [PATCH 19/32] clutter/keymap: Add API to update/get layout names
It's up to the backend to set the names, and the getters are
opportunistic, i.e. will return NULL if none is available.
The names comes from the keymap description.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit bafbde3f2c47e224beff9547bf9254f7cff79a17)
---
clutter/clutter/clutter-keymap-private.h | 5 ++
clutter/clutter/clutter-keymap.c | 67 +++++++++++++++++++
clutter/clutter/clutter-keymap.h | 18 +++++
.../native/meta-keymap-native-private.h | 4 +-
src/backends/native/meta-keymap-native.c | 15 ++++-
src/backends/native/meta-seat-impl.c | 10 ++-
6 files changed, 114 insertions(+), 5 deletions(-)
diff --git a/clutter/clutter/clutter-keymap-private.h b/clutter/clutter/clutter-keymap-private.h
index 5b65b880aa..2b52666bce 100644
--- a/clutter/clutter/clutter-keymap-private.h
+++ b/clutter/clutter/clutter-keymap-private.h
@@ -29,3 +29,8 @@ gboolean clutter_keymap_update_state (ClutterKeymap *keymap,
xkb_mod_mask_t latched_mods,
xkb_mod_mask_t locked_mods,
gboolean emit_signal);
+
+CLUTTER_EXPORT
+void clutter_keymap_update_keymap_names (ClutterKeymap *keymap,
+ GStrv display_names,
+ GStrv short_names);
diff --git a/clutter/clutter/clutter-keymap.c b/clutter/clutter/clutter-keymap.c
index 4073da4f17..ddcf568f78 100644
--- a/clutter/clutter/clutter-keymap.c
+++ b/clutter/clutter/clutter-keymap.c
@@ -44,6 +44,9 @@ typedef struct _ClutterKeymapPrivate
xkb_mod_mask_t locked_mods;
xkb_layout_index_t effective_layout_group;
+
+ GStrv display_names;
+ GStrv short_names;
} ClutterKeymapPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterKeymap, clutter_keymap,
@@ -103,6 +106,18 @@ clutter_keymap_set_property (GObject *object,
}
}
+static void
+clutter_keymap_finalize (GObject *object)
+{
+ ClutterKeymap *keymap = CLUTTER_KEYMAP (object);
+ ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
+
+ g_clear_pointer (&priv->display_names, g_strfreev);
+ g_clear_pointer (&priv->short_names, g_strfreev);
+
+ G_OBJECT_CLASS (clutter_keymap_parent_class)->finalize (object);
+}
+
static void
clutter_keymap_class_init (ClutterKeymapClass *klass)
{
@@ -110,6 +125,7 @@ clutter_keymap_class_init (ClutterKeymapClass *klass)
object_class->get_property = clutter_keymap_get_property;
object_class->set_property = clutter_keymap_set_property;
+ object_class->finalize = clutter_keymap_finalize;
obj_props[PROP_CAPS_LOCK_STATE] =
g_param_spec_boolean ("caps-lock-state", NULL, NULL,
@@ -208,6 +224,19 @@ clutter_keymap_update_state (ClutterKeymap *keymap,
return TRUE;
}
+void
+clutter_keymap_update_keymap_names (ClutterKeymap *keymap,
+ GStrv display_names,
+ GStrv short_names)
+{
+ ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
+
+ g_clear_pointer (&priv->display_names, g_strfreev);
+ g_clear_pointer (&priv->short_names, g_strfreev);
+ priv->display_names = g_steal_pointer (&display_names);
+ priv->short_names = g_steal_pointer (&short_names);
+}
+
void
clutter_keymap_get_modifier_state (ClutterKeymap *keymap,
xkb_mod_mask_t *depressed_mods,
@@ -228,3 +257,41 @@ clutter_keymap_get_layout_index (ClutterKeymap *keymap)
return priv->effective_layout_group;
}
+
+const char *
+clutter_keymap_get_current_display_name (ClutterKeymap *keymap)
+{
+ ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
+ char *display_name;
+
+ if (!priv->display_names)
+ return NULL;
+
+ if (g_strv_length (priv->display_names) <= priv->effective_layout_group)
+ return NULL;
+
+ display_name = priv->display_names[priv->effective_layout_group];
+ if (g_strcmp0 (display_name, "") == 0)
+ return NULL;
+ else
+ return display_name;
+}
+
+const char *
+clutter_keymap_get_current_short_name (ClutterKeymap *keymap)
+{
+ ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
+ char *short_name;
+
+ if (!priv->short_names)
+ return NULL;
+
+ if (g_strv_length (priv->display_names) <= priv->effective_layout_group)
+ return NULL;
+
+ short_name = priv->short_names[priv->effective_layout_group];
+ if (g_strcmp0 (short_name, "") == 0)
+ return NULL;
+ else
+ return short_name;
+}
diff --git a/clutter/clutter/clutter-keymap.h b/clutter/clutter/clutter-keymap.h
index a40a90c823..eb28db39b0 100644
--- a/clutter/clutter/clutter-keymap.h
+++ b/clutter/clutter/clutter-keymap.h
@@ -68,3 +68,21 @@ void clutter_keymap_get_modifier_state (ClutterKeymap *keymap,
*/
CLUTTER_EXPORT
xkb_layout_index_t clutter_keymap_get_layout_index (ClutterKeymap *keymap);
+
+/**
+ * clutter_keymap_get_current_display_name:
+ * @keymap: A #ClutterKeymap
+ *
+ * Returns: (transfer none) (nullable): The display name of the current layout
+ */
+CLUTTER_EXPORT
+const char * clutter_keymap_get_current_display_name (ClutterKeymap *keymap);
+
+/**
+ * clutter_keymap_get_current_short_name:
+ * @keymap: A #ClutterKeymap
+ *
+ * Returns: (transfer none) (nullable): The short name of the current layout
+ */
+CLUTTER_EXPORT
+const char * clutter_keymap_get_current_short_name (ClutterKeymap *keymap);
diff --git a/src/backends/native/meta-keymap-native-private.h b/src/backends/native/meta-keymap-native-private.h
index 82d249eda8..e119b91c31 100644
--- a/src/backends/native/meta-keymap-native-private.h
+++ b/src/backends/native/meta-keymap-native-private.h
@@ -29,7 +29,9 @@ void meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
MetaSeatImpl *seat_impl,
MetaKeymapDescription *keymap_description,
struct xkb_keymap *xkb_keymap,
- struct xkb_state *xkb_state);
+ struct xkb_state *xkb_state,
+ GStrv display_names,
+ GStrv short_names);
struct xkb_keymap * meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap);
diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c
index 63f5b4cf29..f55b8bd056 100644
--- a/src/backends/native/meta-keymap-native.c
+++ b/src/backends/native/meta-keymap-native.c
@@ -163,6 +163,9 @@ typedef struct
MetaKeymapDescription *keymap_description;
ModifierState modifier_state;
+
+ GStrv display_names;
+ GStrv short_names;
} UpdateKeymapData;
static void
@@ -171,6 +174,8 @@ update_keymap_data_free (gpointer user_data)
UpdateKeymapData *data = user_data;
meta_keymap_description_unref (data->keymap_description);
+ g_strfreev (data->display_names);
+ g_strfreev (data->short_names);
g_free (data);
}
@@ -181,6 +186,10 @@ update_keymap_in_main (gpointer user_data)
MetaKeymapNative *keymap_native = data->keymap_native;
gboolean state_changed;
+ clutter_keymap_update_keymap_names (CLUTTER_KEYMAP (keymap_native),
+ g_steal_pointer (&data->display_names),
+ g_steal_pointer (&data->short_names));
+
state_changed = update_state_from_modifier_state (keymap_native,
&data->modifier_state,
FALSE);
@@ -198,7 +207,9 @@ meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
MetaSeatImpl *seat_impl,
MetaKeymapDescription *keymap_description,
struct xkb_keymap *xkb_keymap,
- struct xkb_state *xkb_state)
+ struct xkb_state *xkb_state,
+ GStrv display_names,
+ GStrv short_names)
{
UpdateKeymapData *data;
@@ -211,6 +222,8 @@ meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
data->keymap_native = keymap;
data->modifier_state = calculate_modifier_state (xkb_state);
data->keymap_description = meta_keymap_description_ref (keymap_description);
+ data->display_names = g_steal_pointer (&display_names);
+ data->short_names = g_steal_pointer (&short_names);
meta_seat_impl_queue_main_thread_idle (seat_impl,
update_keymap_in_main,
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index a5d490d12b..8a429dc2ec 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3851,14 +3851,16 @@ set_keyboard_map (GTask *task)
MetaKeymapNative *keymap;
g_autoptr (GError) error = NULL;
struct xkb_keymap *xkb_keymap;
+ g_auto (GStrv) display_names = NULL;
+ g_auto (GStrv) short_names = NULL;
g_task_set_priority (task, G_PRIORITY_HIGH);
keymap = seat_impl->keymap;
xkb_keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
- NULL,
- NULL,
+ &display_names,
+ &short_names,
&error);
if (!xkb_keymap)
{
@@ -3877,7 +3879,9 @@ set_keyboard_map (GTask *task)
seat_impl,
keymap_description,
xkb_keymap,
- seat_impl->xkb);
+ seat_impl->xkb,
+ g_steal_pointer (&display_names),
+ g_steal_pointer (&short_names));
xkb_keymap_unref (xkb_keymap);
g_rw_lock_writer_unlock (&seat_impl->state_lock);
--
2.54.0
From 949bfcc52cae826b15785d462104cc299bbddfd4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 10:55:13 +0200
Subject: [PATCH 20/32] wayland/keyboard: Get the current layout index after
keymap changes
The current layout index will potentially have changed together with the
keymap, so don't assume it was left unchanged.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit af4ca9a925e87a303a652da13931d4aeed872afc)
---
src/wayland/meta-wayland-keyboard.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index d7e044c458..451c9d834d 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -159,6 +159,7 @@ static void
meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
struct xkb_keymap *keymap)
{
+ MetaBackend *backend = backend_from_keyboard (keyboard);
MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
char *keymap_string;
size_t keymap_size;
@@ -198,6 +199,7 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
inform_clients_of_new_keymap (keyboard);
+ keyboard->xkb_info.group = meta_backend_get_keymap_layout_group (backend);
notify_modifiers (keyboard);
}
--
2.54.0
From 752d689006a19a573743dd3ae74cb6f39d61ed6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 11:19:07 +0200
Subject: [PATCH 21/32] backend: Add signals to 'reset' the keymap and layout
index
This allows users of libmutter to fall back on any previously used
keyboard layout once a locked keymap description is unset.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 6279a85c31710610d551fd71d209dc8cee191f1d)
---
src/backends/meta-backend-private.h | 9 ++++
src/backends/meta-backend.c | 70 +++++++++++++++++++++++++++++
src/compositor/plugins/default.c | 34 ++++++++++++++
3 files changed, 113 insertions(+)
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index dccd1116a6..e3b4c308db 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -217,6 +217,15 @@ struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
META_EXPORT_TEST
xkb_layout_index_t meta_backend_get_keymap_layout_group (MetaBackend *backend);
+gboolean meta_backend_reset_keymap_finish (MetaBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+
+void meta_backend_reset_keymap_async (MetaBackend *backend,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
gboolean meta_backend_is_lid_closed (MetaBackend *backend);
void meta_backend_set_client_pointer_constraint (MetaBackend *backend,
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index beaec1f281..031c0a03cb 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -122,6 +122,8 @@ enum
LID_IS_CLOSED_CHANGED,
GPU_ADDED,
PREPARE_SHUTDOWN,
+ RESET_KEYMAP_DESCRIPTION,
+ RESET_KEYMAP_LAYOUT_INDEX,
N_SIGNALS
};
@@ -963,6 +965,20 @@ meta_backend_class_init (MetaBackendClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
+ signals[RESET_KEYMAP_DESCRIPTION] =
+ g_signal_new ("reset-keymap-description",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_first_wins, NULL, NULL,
+ META_TYPE_KEYMAP_DESCRIPTION, 0);
+ signals[RESET_KEYMAP_LAYOUT_INDEX] =
+ g_signal_new ("reset-keymap-layout-index",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_first_wins, NULL, NULL,
+ G_TYPE_UINT, 0);
}
#ifdef HAVE_LOGIND
@@ -1851,6 +1867,60 @@ meta_backend_set_keymap_layout_group_async (MetaBackend *backend,
task);
}
+gboolean
+meta_backend_reset_keymap_finish (MetaBackend *backend,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTask *task = G_TASK (result);
+
+ g_return_val_if_fail (g_task_is_valid (result, backend), FALSE);
+ g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
+ meta_backend_reset_keymap_async, FALSE);
+
+ return g_task_propagate_boolean (task, error);
+}
+
+void
+meta_backend_reset_keymap_async (MetaBackend *backend,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
+ uint32_t layout_index = 0;
+ GTask *task;
+
+ g_signal_emit (backend,
+ signals[RESET_KEYMAP_DESCRIPTION], 0,
+ &keymap_description);
+ g_signal_emit (backend,
+ signals[RESET_KEYMAP_LAYOUT_INDEX], 0,
+ &layout_index);
+
+ if (!keymap_description)
+ {
+ g_warning ("No fallback keymap description available, "
+ "falling batk to 'us'");
+ keymap_description =
+ meta_keymap_description_new_from_rules (NULL,
+ "us",
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ layout_index = 0;
+ }
+
+ task = g_task_new (G_OBJECT (backend), cancellable, callback, user_data);
+ g_task_set_source_tag (task, meta_backend_reset_keymap_async);
+
+ META_BACKEND_GET_CLASS (backend)->set_keymap_async (backend,
+ keymap_description,
+ layout_index,
+ task);
+}
+
/**
* meta_backend_get_stage:
* @backend: A #MetaBackend
diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c
index cbce7ab959..cc11c2df8a 100644
--- a/src/compositor/plugins/default.c
+++ b/src/compositor/plugins/default.c
@@ -117,6 +117,8 @@ struct _MetaDefaultPluginPrivate
ClutterActor *desktop2;
ClutterActor *background_group;
+
+ MetaKeymapDescription *keymap_description;
};
META_PLUGIN_DECLARE_WITH_CODE (MetaDefaultPlugin, meta_default_plugin,
@@ -149,11 +151,24 @@ typedef struct _DisplayTilePreview
MtkRectangle tile_rect;
} DisplayTilePreview;
+static void
+meta_default_plugin_finalize (GObject *object)
+{
+ MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (object)->priv;
+
+ g_clear_pointer (&priv->keymap_description, meta_keymap_description_unref);
+
+ G_OBJECT_CLASS (meta_default_plugin_parent_class)->finalize (object);
+}
+
static void
meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
+ object_class->finalize = meta_default_plugin_finalize;
+
plugin_class->start = start;
plugin_class->map = map;
plugin_class->minimize = minimize;
@@ -356,6 +371,7 @@ static void
init_keymap (MetaDefaultPlugin *self,
MetaBackend *backend)
{
+ MetaDefaultPluginPrivate *priv = self->priv;
g_autoptr (GError) error = NULL;
g_autoptr (GDBusProxy) proxy = NULL;
g_autoptr (GVariant) result = NULL;
@@ -424,6 +440,9 @@ init_keymap (MetaDefaultPlugin *self,
meta_backend_set_keymap_async (backend,
keymap_description, 0,
NULL, NULL, NULL);
+
+
+ priv->keymap_description = meta_keymap_description_ref (keymap_description);
}
static void
@@ -433,6 +452,18 @@ prepare_shutdown (MetaBackend *backend,
kill_switch_workspace (META_PLUGIN (plugin));
}
+static MetaKeymapDescription *
+on_reset_keymap_description (MetaBackend *backend,
+ MetaDefaultPlugin *self)
+{
+ MetaDefaultPluginPrivate *priv = self->priv;
+
+ if (priv->keymap_description)
+ return meta_keymap_description_ref (priv->keymap_description);
+ else
+ return NULL;
+}
+
static void
start (MetaPlugin *plugin)
{
@@ -453,6 +484,9 @@ start (MetaPlugin *plugin)
on_monitors_changed (monitor_manager, plugin);
+ g_signal_connect (backend, "reset-keymap-description",
+ G_CALLBACK (on_reset_keymap_description), self);
+
g_signal_connect (backend, "prepare-shutdown",
G_CALLBACK (prepare_shutdown),
self);
--
2.54.0
From 74ea326e9b6ceeb9ea42180918fb6422099fd54f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Mon, 15 Dec 2025 13:27:00 +0100
Subject: [PATCH 22/32] backend: Combine set_keymap() and
set_keymap_layout_group()
We can already skip changing the actual keymap by comparing whether the
keymap description was replaced by some other one, meaning the the
layout index only API is redundant.
Doing this also allows us to avoid a race condition where one entity
sets the layout index on a description that was just replaced by another
entity. This is now resolved by the layout index change replacing also
the keymap, but in theory this can be now be tweaked, would we want to,
by adding flags.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 5cc1cd137d88971d289f30f80cde56d991413a92)
---
src/backends/meta-backend-private.h | 4 -
src/backends/meta-backend.c | 31 ----
src/backends/native/meta-backend-native.c | 49 ------
src/backends/native/meta-seat-impl.c | 185 +++++++++-------------
src/backends/native/meta-seat-impl.h | 10 --
src/backends/native/meta-seat-native.c | 70 --------
src/backends/native/meta-seat-native.h | 10 --
src/tests/keyboard-map-tests.c | 29 ++--
8 files changed, 99 insertions(+), 289 deletions(-)
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index e3b4c308db..c82d41032d 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -135,10 +135,6 @@ struct _MetaBackendClass
xkb_layout_index_t (* get_keymap_layout_group) (MetaBackend *backend);
- void (* set_keymap_layout_group_async) (MetaBackend *backend,
- xkb_layout_index_t idx,
- GTask *task);
-
void (* update_stage) (MetaBackend *backend);
void (* select_stage_events) (MetaBackend *backend);
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 031c0a03cb..03ebf27ee4 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -1836,37 +1836,6 @@ meta_backend_get_keymap_layout_group (MetaBackend *backend)
return META_BACKEND_GET_CLASS (backend)->get_keymap_layout_group (backend);
}
-gboolean
-meta_backend_set_keymap_layout_group_finish (MetaBackend *backend,
- GAsyncResult *result,
- GError **error)
-{
- GTask *task = G_TASK (result);
-
- g_return_val_if_fail (g_task_is_valid (result, backend), FALSE);
- g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
- meta_backend_set_keymap_layout_group_async, FALSE);
-
- return g_task_propagate_boolean (task, error);
-}
-
-void
-meta_backend_set_keymap_layout_group_async (MetaBackend *backend,
- uint32_t idx,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
-
- task = g_task_new (G_OBJECT (backend), cancellable, callback, user_data);
- g_task_set_source_tag (task, meta_backend_set_keymap_layout_group_async);
-
- META_BACKEND_GET_CLASS (backend)->set_keymap_layout_group_async (backend,
- idx,
- task);
-}
-
gboolean
meta_backend_reset_keymap_finish (MetaBackend *backend,
GAsyncResult *result,
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index b2efac59d1..7d68894cb8 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -384,54 +384,6 @@ meta_backend_native_get_keymap_layout_group (MetaBackend *backend)
return meta_seat_native_get_keyboard_layout_index (META_SEAT_NATIVE (seat));
}
-static void
-set_layout_index_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- MetaSeatNative *seat_native = META_SEAT_NATIVE (source_object);
- g_autoptr (GTask) task = G_TASK (user_data);
- MetaBackend *backend = META_BACKEND (g_task_get_source_object (task));
- g_autoptr (GError) error = NULL;
- gboolean index_changed;
-
- index_changed =
- meta_seat_native_set_keyboard_layout_index_finish (seat_native,
- result,
- &error);
- if (error)
- {
- g_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- if (index_changed)
- {
- xkb_layout_index_t idx;
-
- idx = meta_seat_native_get_keyboard_layout_index (seat_native);
- meta_backend_notify_keymap_layout_group_changed (backend, idx);
- }
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-meta_backend_native_set_keymap_layout_group_async (MetaBackend *backend,
- xkb_layout_index_t idx,
- GTask *task)
-{
- ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
- ClutterSeat *seat;
-
- seat = clutter_backend_get_default_seat (clutter_backend);
- meta_seat_native_set_keyboard_layout_index_async (META_SEAT_NATIVE (seat),
- idx,
- g_task_get_cancellable (task),
- set_layout_index_cb,
- task);
-}
-
static gboolean
meta_backend_native_is_headless (MetaBackend *backend)
{
@@ -954,7 +906,6 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
backend_class->get_keymap = meta_backend_native_get_keymap;
backend_class->get_keymap_description = meta_backend_native_get_keymap_description;
backend_class->get_keymap_layout_group = meta_backend_native_get_keymap_layout_group;
- backend_class->set_keymap_layout_group_async = meta_backend_native_set_keymap_layout_group_async;
backend_class->update_stage = meta_backend_native_update_stage;
backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint;
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index 8a429dc2ec..7c94a6c5cc 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -133,6 +133,8 @@ typedef struct _MetaSeatImplPrivate
uint32_t last_keysym_time;
gboolean saw_first_release;
} a11y;
+
+ MetaKeymapDescription *keymap_description;
} MetaSeatImplPrivate;
static void meta_seat_impl_initable_iface_init (GInitableIface *iface);
@@ -3403,6 +3405,7 @@ static void
meta_seat_impl_finalize (GObject *object)
{
MetaSeatImpl *seat_impl = META_SEAT_IMPL (object);
+ MetaSeatImplPrivate *priv = meta_seat_impl_get_instance_private (seat_impl);
g_assert (!seat_impl->libinput);
g_assert (!seat_impl->tools);
@@ -3410,6 +3413,9 @@ meta_seat_impl_finalize (GObject *object)
g_free (seat_impl->seat_id);
+ g_clear_pointer (&priv->keymap_description,
+ meta_keymap_description_unref);
+
g_rw_lock_clear (&seat_impl->state_lock);
G_OBJECT_CLASS (meta_seat_impl_parent_class)->finalize (object);
@@ -3842,47 +3848,92 @@ set_keymap_data_free (gpointer user_data)
g_free (data);
}
+static void
+update_layout_index_unlocked (MetaSeatImpl *seat_impl,
+ xkb_layout_index_t layout_index)
+{
+ xkb_mod_mask_t depressed_mods;
+ xkb_mod_mask_t latched_mods;
+ xkb_mod_mask_t locked_mods;
+ struct xkb_state *state;
+
+ state = seat_impl->xkb;
+
+ depressed_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED);
+ latched_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED);
+ locked_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED);
+
+ xkb_state_update_mask (state,
+ depressed_mods,
+ latched_mods,
+ locked_mods,
+ 0, 0, layout_index);
+
+ seat_impl->layout_idx = layout_index;
+
+ meta_seat_impl_sync_leds_in_impl (seat_impl);
+ meta_keymap_native_update_in_impl (seat_impl->keymap,
+ seat_impl,
+ seat_impl->xkb);
+}
+
static gboolean
set_keyboard_map (GTask *task)
{
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
+ MetaSeatImplPrivate *priv =
+ meta_seat_impl_get_instance_private (seat_impl);
SetKeymapData *data = g_task_get_task_data (task);
MetaKeymapDescription *keymap_description = data->keymap_description;
MetaKeymapNative *keymap;
- g_autoptr (GError) error = NULL;
- struct xkb_keymap *xkb_keymap;
- g_auto (GStrv) display_names = NULL;
- g_auto (GStrv) short_names = NULL;
g_task_set_priority (task, G_PRIORITY_HIGH);
- keymap = seat_impl->keymap;
-
- xkb_keymap = meta_keymap_description_create_xkb_keymap (keymap_description,
- &display_names,
- &short_names,
- &error);
- if (!xkb_keymap)
- {
- g_prefix_error (&error, "Unable to load configured keymap: ");
- g_task_return_error (task, g_steal_pointer (&error));
- return G_SOURCE_REMOVE;
- }
-
g_rw_lock_writer_lock (&seat_impl->state_lock);
- meta_seat_impl_update_xkb_state_in_impl_unlocked (seat_impl,
- xkb_keymap,
- data->layout_index);
+ if (priv->keymap_description != keymap_description)
+ {
+ g_autoptr (GError) error = NULL;
+ g_auto (GStrv) display_names = NULL;
+ g_auto (GStrv) short_names = NULL;
+ struct xkb_keymap *xkb_keymap = NULL;
+
+ g_clear_pointer (&priv->keymap_description,
+ meta_keymap_description_unref);
+ priv->keymap_description =
+ meta_keymap_description_ref (keymap_description);
+
+ xkb_keymap =
+ meta_keymap_description_create_xkb_keymap (keymap_description,
+ &display_names,
+ &short_names,
+ &error);
+ if (!xkb_keymap)
+ {
+ g_prefix_error (&error, "Unable to load configured keymap: ");
+ g_task_return_error (task, g_steal_pointer (&error));
+ g_rw_lock_writer_unlock (&seat_impl->state_lock);
+ return G_SOURCE_REMOVE;
+ }
- meta_keymap_native_set_keyboard_map_in_impl (keymap,
- seat_impl,
- keymap_description,
- xkb_keymap,
- seat_impl->xkb,
- g_steal_pointer (&display_names),
- g_steal_pointer (&short_names));
- xkb_keymap_unref (xkb_keymap);
+ meta_seat_impl_update_xkb_state_in_impl_unlocked (seat_impl,
+ xkb_keymap,
+ data->layout_index);
+
+ keymap = seat_impl->keymap;
+ meta_keymap_native_set_keyboard_map_in_impl (keymap,
+ seat_impl,
+ keymap_description,
+ xkb_keymap,
+ seat_impl->xkb,
+ g_steal_pointer (&display_names),
+ g_steal_pointer (&short_names));
+ xkb_keymap_unref (xkb_keymap);
+ }
+ else
+ {
+ update_layout_index_unlocked (seat_impl, data->layout_index);
+ }
g_rw_lock_writer_unlock (&seat_impl->state_lock);
@@ -3929,84 +3980,6 @@ meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
g_object_unref (task);
}
-gboolean
-meta_seat_impl_set_keyboard_layout_index_finish (MetaSeatImpl *seat_impl,
- GAsyncResult *result,
- GError **error)
-{
- GTask *task = G_TASK (result);
-
- g_return_val_if_fail (g_task_is_valid (result, seat_impl), FALSE);
- g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
- meta_seat_impl_set_keyboard_layout_index_async,
- FALSE);
-
- return g_task_propagate_boolean (task, error);
-}
-
-static gboolean
-set_keyboard_layout_index (GTask *task)
-{
- MetaSeatImpl *seat_impl = g_task_get_source_object (task);
- xkb_layout_index_t idx = GPOINTER_TO_UINT (g_task_get_task_data (task));
- xkb_mod_mask_t depressed_mods;
- xkb_mod_mask_t latched_mods;
- xkb_mod_mask_t locked_mods;
- struct xkb_state *state;
-
- g_rw_lock_writer_lock (&seat_impl->state_lock);
-
- state = seat_impl->xkb;
-
- depressed_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED);
- latched_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED);
- locked_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED);
-
- xkb_state_update_mask (state, depressed_mods, latched_mods, locked_mods, 0, 0, idx);
-
- seat_impl->layout_idx = idx;
-
- g_task_return_boolean (task, TRUE);
-
- meta_seat_impl_sync_leds_in_impl (seat_impl);
- meta_keymap_native_update_in_impl (seat_impl->keymap,
- seat_impl,
- seat_impl->xkb);
-
- g_rw_lock_writer_unlock (&seat_impl->state_lock);
-
- return G_SOURCE_REMOVE;
-}
-
-/**
- * meta_seat_impl_set_keyboard_layout_index_async: (skip)
- * @seat_impl: the #ClutterSeat created by the evdev backend
- * @idx: the xkb layout index to set
- * @cancellable: a #GCancellable
- * @callback: callback to call when index has changed
- * @user_data: user data to pass to the callback
- *
- * Sets the xkb layout index on the backend's #xkb_state .
- */
-void
-meta_seat_impl_set_keyboard_layout_index_async (MetaSeatImpl *seat_impl,
- xkb_layout_index_t idx,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
-
- g_return_if_fail (META_IS_SEAT_IMPL (seat_impl));
-
- task = g_task_new (seat_impl, cancellable, callback, user_data);
- g_task_set_source_tag (task, meta_seat_impl_set_keyboard_layout_index_async);
- g_task_set_task_data (task, GUINT_TO_POINTER (idx), NULL);
- meta_seat_impl_run_input_task (seat_impl, task,
- (GSourceFunc) set_keyboard_layout_index);
- g_object_unref (task);
-}
-
/**
* meta_seat_impl_set_keyboard_repeat_in_impl:
* @seat_impl: the #ClutterSeat created by the evdev backend
diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h
index 4950a19a74..c4692cac19 100644
--- a/src/backends/native/meta-seat-impl.h
+++ b/src/backends/native/meta-seat-impl.h
@@ -196,16 +196,6 @@ void meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
GAsyncReadyCallback callback,
gpointer user_data);
-gboolean meta_seat_impl_set_keyboard_layout_index_finish (MetaSeatImpl *seat_impl,
- GAsyncResult *result,
- GError **error);
-
-void meta_seat_impl_set_keyboard_layout_index_async (MetaSeatImpl *seat_impl,
- xkb_layout_index_t idx,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
void meta_seat_impl_set_keyboard_repeat_in_impl (MetaSeatImpl *seat_impl,
gboolean repeat,
uint32_t delay,
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 5498bac13f..2722b1d970 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -731,76 +731,6 @@ meta_seat_native_get_keyboard_map_description (MetaSeatNative *seat_native)
return seat_native->keymap_description;
}
-gboolean
-meta_seat_native_set_keyboard_layout_index_finish (MetaSeatNative *seat_native,
- GAsyncResult *result,
- GError **error)
-{
- GTask *task = G_TASK (result);
-
- g_return_val_if_fail (g_task_is_valid (result, seat_native), FALSE);
- g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
- meta_seat_native_set_keyboard_layout_index_async,
- FALSE);
-
- return g_task_propagate_boolean (task, error);
-}
-
-static void
-set_seat_impl_layout_index_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- MetaSeatImpl *seat_impl = META_SEAT_IMPL (source_object);
- g_autoptr (GTask) task = user_data;
- MetaSeatNative *seat_native =
- META_SEAT_NATIVE (g_task_get_source_object (task));
- g_autoptr (GError) error = NULL;
- xkb_layout_index_t idx = GPOINTER_TO_UINT (g_task_get_task_data (task));
- xkb_layout_index_t old_idx;
-
- if (!meta_seat_impl_set_keyboard_layout_index_finish (seat_impl,
- result,
- &error))
- {
- g_task_return_error (task, error);
- return;
- }
-
- old_idx = seat_native->xkb_layout_index;
- seat_native->xkb_layout_index = idx;
-
- g_task_return_boolean (task, old_idx != idx);
-}
-
-/**
- * meta_seat_native_set_keyboard_layout_index_async: (skip)
- * @seat: the #ClutterSeat created by the evdev backend
- * @idx: the xkb layout index to set
- *
- * Sets the xkb layout index on the backend's #xkb_state .
- */
-void
-meta_seat_native_set_keyboard_layout_index_async (MetaSeatNative *seat_native,
- xkb_layout_index_t idx,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr (GTask) task = NULL;
-
- g_return_if_fail (META_IS_SEAT_NATIVE (seat_native));
-
- task = g_task_new (G_OBJECT (seat_native), cancellable, callback, user_data);
- g_task_set_source_tag (task, meta_seat_native_set_keyboard_layout_index_async);
- g_task_set_task_data (task, GUINT_TO_POINTER (idx), NULL);
-
- meta_seat_impl_set_keyboard_layout_index_async (seat_native->impl, idx,
- cancellable,
- set_seat_impl_layout_index_cb,
- g_steal_pointer (&task));
-}
-
/**
* meta_seat_native_get_keyboard_layout_index: (skip)
*/
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index 061b580bc2..7fbe7dd3e7 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -115,16 +115,6 @@ gboolean meta_seat_native_set_keyboard_map_finish (MetaSeatNative *seat_native,
META_EXPORT_TEST
struct xkb_keymap * meta_seat_native_get_keyboard_map (MetaSeatNative *seat);
-gboolean meta_seat_native_set_keyboard_layout_index_finish (MetaSeatNative *seat_native,
- GAsyncResult *result,
- GError **error);
-
-void meta_seat_native_set_keyboard_layout_index_async (MetaSeatNative *seat,
- xkb_layout_index_t idx,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
MetaKeymapDescription * meta_seat_native_get_keyboard_map_description (MetaSeatNative *seat_native);
xkb_layout_index_t meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat);
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index e1a65214cc..7d233dbe23 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -275,14 +275,18 @@ set_keymap_layout_group_cb (GObject *source_object,
gboolean *done = user_data;
g_autoptr (GError) error = NULL;
- g_assert_true (meta_backend_set_keymap_layout_group_finish (backend,
- result,
- &error));
+ g_assert_true (meta_backend_set_keymap_finish (backend, result, &error));
g_assert_no_error (error);
*done = TRUE;
}
+static void
+trigger_error (const char *message)
+{
+ g_error ("%s", message);
+}
+
static void
meta_test_native_keyboard_map_set_layout_index (void)
{
@@ -290,6 +294,7 @@ meta_test_native_keyboard_map_set_layout_index (void)
g_autoptr (MetaKeymapDescription) keymap_description = NULL;
gboolean done = FALSE;
struct xkb_keymap *keymap;
+ gulong keymap_changed_handler_id;
keymap_description =
meta_keymap_description_new_from_rules (NULL,
@@ -303,10 +308,15 @@ meta_test_native_keyboard_map_set_layout_index (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
+ keymap_changed_handler_id =
+ g_signal_connect_swapped (backend,
+ "keymap-changed",
+ G_CALLBACK (trigger_error),
+ (gpointer) "Unexpected keymap-changed emission");
+
done = FALSE;
- meta_backend_set_keymap_layout_group_async (backend, 0, NULL,
- set_keymap_layout_group_cb,
- &done);
+ meta_backend_set_keymap_async (backend, keymap_description, 0,
+ NULL, set_keymap_layout_group_cb, &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
@@ -321,13 +331,14 @@ meta_test_native_keyboard_map_set_layout_index (void)
g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
done = FALSE;
- meta_backend_set_keymap_layout_group_async (backend, 1, NULL,
- set_keymap_layout_group_cb,
- &done);
+ meta_backend_set_keymap_async (backend, keymap_description, 1,
+ NULL, set_keymap_layout_group_cb, &done);
g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
while (!done)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 1);
+
+ g_signal_handler_disconnect (backend, keymap_changed_handler_id);
}
static void
--
2.54.0
From 47acb440846860210d7b945e34dd87ee2c4ba167 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 10:56:52 +0200
Subject: [PATCH 23/32] keymap-description: Add way to 'lock' a keymap
description
This should be interpreted by other entities that tries to set the
keymap to avoid doing so. It's meant to allow a remote desktop service
to be in control of the current keymap and keyboard layout.
This introduces a concept of keymap description owner. Only the same
owner can set a new keymap if a current keymap description is locked.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit b1344b5f09d032ee1c44c31ef742b418ce74bb24)
---
.../meta-keymap-description-private.h | 21 +++
src/backends/meta-keymap-description.c | 68 ++++++++
src/backends/native/meta-seat-impl.c | 13 ++
src/meta/meta-keymap-description.h | 3 +
src/tests/keyboard-map-tests.c | 165 ++++++++++++++++++
5 files changed, 270 insertions(+)
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index 3c0d9cc924..5bf0b25505 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -21,6 +21,7 @@
#include "meta/meta-keymap-description.h"
#include "core/meta-sealed-fd.h"
+#include "core/util-private.h"
typedef enum _MetaKeymapDescriptionSource
{
@@ -28,6 +29,16 @@ typedef enum _MetaKeymapDescriptionSource
META_KEYMAP_DESCRIPTION_SOURCE_FD,
} MetaKeymapDescriptionSource;
+typedef struct _MetaKeymapDescriptionOwner MetaKeymapDescriptionOwner;
+
+META_EXPORT_TEST
+MetaKeymapDescriptionOwner * meta_keymap_description_owner_new (void);
+
+MetaKeymapDescriptionOwner * meta_keymap_description_owner_ref (MetaKeymapDescriptionOwner *owner);
+
+META_EXPORT_TEST
+void meta_keymap_description_owner_unref (MetaKeymapDescriptionOwner *owner);
+
MetaKeymapDescription * meta_keymap_description_new_from_fd (MetaSealedFd *sealed_fd,
enum xkb_keymap_format format);
@@ -37,3 +48,13 @@ struct xkb_keymap * meta_keymap_description_create_xkb_keymap (MetaKeymapDescrip
GStrv *out_display_names,
GStrv *out_short_names,
GError **error);
+
+META_EXPORT_TEST
+void meta_keymap_description_lock (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescriptionOwner *owner);
+
+META_EXPORT_TEST
+void meta_keymap_description_unlock (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescriptionOwner *owner);
+
+MetaKeymapDescriptionOwner * meta_keymap_description_get_owner (MetaKeymapDescription *keymap_description);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index 63bd539d57..b67bcf0a74 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -26,12 +26,20 @@
#include "backends/meta-keymap-utils.h"
#include "core/meta-sealed-fd.h"
+struct _MetaKeymapDescriptionOwner
+{
+ gatomicrefcount ref_count;
+};
+
struct _MetaKeymapDescription
{
gatomicrefcount ref_count;
MetaKeymapDescriptionSource source;
+ gboolean is_locked;
+ MetaKeymapDescriptionOwner *owner;
+
union {
struct {
char *rules;
@@ -62,6 +70,31 @@ strdup_or_empty (const char *string)
return string ? g_strdup (string) : g_strdup ("");
}
+MetaKeymapDescriptionOwner *
+meta_keymap_description_owner_new (void)
+{
+ MetaKeymapDescriptionOwner *owner;
+
+ owner = g_new0 (MetaKeymapDescriptionOwner, 1);
+ g_atomic_ref_count_init (&owner->ref_count);
+
+ return owner;
+}
+
+MetaKeymapDescriptionOwner *
+meta_keymap_description_owner_ref (MetaKeymapDescriptionOwner *owner)
+{
+ g_atomic_ref_count_inc (&owner->ref_count);
+ return owner;
+}
+
+void
+meta_keymap_description_owner_unref (MetaKeymapDescriptionOwner *owner)
+{
+ if (g_atomic_ref_count_dec (&owner->ref_count))
+ g_free (owner);
+}
+
MetaKeymapDescription *
meta_keymap_description_new_from_rules (const char *model,
const char *layout,
@@ -128,6 +161,9 @@ meta_keymap_description_unref (MetaKeymapDescription *keymap_description)
break;
}
+ g_clear_pointer (&keymap_description->owner,
+ meta_keymap_description_owner_unref);
+
g_free (keymap_description);
}
}
@@ -293,3 +329,35 @@ meta_keymap_description_create_xkb_keymap (MetaKeymapDescription *keymap_descri
return xkb_keymap;
}
+
+void
+meta_keymap_description_lock (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescriptionOwner *owner)
+{
+ g_return_if_fail (!keymap_description->owner);
+
+ keymap_description->is_locked = TRUE;
+ keymap_description->owner = meta_keymap_description_owner_ref (owner);
+}
+
+void
+meta_keymap_description_unlock (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescriptionOwner *owner)
+{
+ g_return_if_fail (!keymap_description->owner);
+ g_return_if_fail (!keymap_description->is_locked);
+
+ keymap_description->owner = meta_keymap_description_owner_ref (owner);
+}
+
+gboolean
+meta_keymap_description_is_locked (MetaKeymapDescription *keymap_description)
+{
+ return keymap_description->is_locked;
+}
+
+MetaKeymapDescriptionOwner *
+meta_keymap_description_get_owner (MetaKeymapDescription *keymap_description)
+{
+ return keymap_description->owner;
+}
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index 7c94a6c5cc..ab8e207d16 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3898,6 +3898,19 @@ set_keyboard_map (GTask *task)
g_auto (GStrv) short_names = NULL;
struct xkb_keymap *xkb_keymap = NULL;
+ if (priv->keymap_description)
+ {
+ if (meta_keymap_description_is_locked (priv->keymap_description) &&
+ meta_keymap_description_get_owner (keymap_description) !=
+ meta_keymap_description_get_owner (priv->keymap_description))
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Keymap locked by other owner");
+ g_rw_lock_writer_unlock (&seat_impl->state_lock);
+ return G_SOURCE_REMOVE;
+ }
+ }
+
g_clear_pointer (&priv->keymap_description,
meta_keymap_description_unref);
priv->keymap_description =
diff --git a/src/meta/meta-keymap-description.h b/src/meta/meta-keymap-description.h
index 5140f63b1a..0f4de5ed2b 100644
--- a/src/meta/meta-keymap-description.h
+++ b/src/meta/meta-keymap-description.h
@@ -42,5 +42,8 @@ MetaKeymapDescription * meta_keymap_description_ref (MetaKeymapDescription *keym
META_EXPORT
void meta_keymap_description_unref (MetaKeymapDescription *keymap_description);
+META_EXPORT
+gboolean meta_keymap_description_is_locked (MetaKeymapDescription *keymap_description);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKeymapDescription,
meta_keymap_description_unref);
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index 7d233dbe23..1bbb87430b 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -21,6 +21,7 @@
#include <linux/input-event-codes.h>
#include "backends/meta-backend-private.h"
+#include "backends/meta-keymap-description-private.h"
#include "backends/native/meta-keymap-native.h"
#include "backends/native/meta-seat-native.h"
#include "tests/meta-test-utils.h"
@@ -35,6 +36,12 @@ typedef struct
static MetaContext *test_context;
+static void
+set_true_cb (gboolean *value)
+{
+ *value = TRUE;
+}
+
static void
set_keymap_cb (GObject *source_object,
GAsyncResult *result,
@@ -50,6 +57,21 @@ set_keymap_cb (GObject *source_object,
*done = TRUE;
}
+static void
+set_keymap_expect_error_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaBackend *backend = META_BACKEND (source_object);
+ gboolean *done = user_data;
+ g_autoptr (GError) error = NULL;
+
+ g_assert_false (meta_backend_set_keymap_finish (backend, result, &error));
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+
+ *done = TRUE;
+}
+
static void
await_mod_mask (MetaKeymapNative *keymap_native,
ModMaskTuple **awaited_mod_mask)
@@ -341,6 +363,147 @@ meta_test_native_keyboard_map_set_layout_index (void)
g_signal_handler_disconnect (backend, keymap_changed_handler_id);
}
+static void
+meta_test_native_keyboard_map_lock_layout (void)
+{
+ MetaBackend *backend = meta_context_get_backend (test_context);
+ g_autoptr (MetaKeymapDescription) keymap_description1 = NULL;
+ g_autoptr (MetaKeymapDescription) keymap_description2 = NULL;
+ g_autoptr (MetaKeymapDescription) keymap_description3 = NULL;
+ MetaKeymapDescriptionOwner *owner;
+ gboolean done = FALSE;
+ gboolean was_signalled;
+ struct xkb_keymap *keymap;
+ gulong keymap_changed_handler_id;
+ gulong keymap_layout_group_changed_handler_id;
+
+ owner = meta_keymap_description_owner_new ();
+
+ /*
+ * Set a locking keymap.
+ */
+
+ keymap_description1 =
+ meta_keymap_description_new_from_rules (NULL,
+ "us,se",
+ "dvorak-alt-intl,svdvorak",
+ NULL,
+ NULL,
+ NULL);
+ meta_keymap_description_lock (keymap_description1, owner);
+ meta_backend_set_keymap_async (backend, keymap_description1, 0,
+ NULL, set_keymap_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ keymap = xkb_keymap_ref (meta_backend_get_keymap (backend));
+ g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
+ g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
+ ==,
+ "English (Dvorak, alt. intl.)");
+ g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 1),
+ ==,
+ "Swedish (Svdvorak)");
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
+
+ /*
+ * Set a new keymap without an owner. Should cause an error and not take
+ * effect.
+ */
+
+ keymap_changed_handler_id =
+ g_signal_connect_swapped (backend,
+ "keymap-changed",
+ G_CALLBACK (trigger_error),
+ (gpointer) "Unexpected keymap-changed emission");
+
+ keymap_description2 =
+ meta_keymap_description_new_from_rules (NULL,
+ "se,us",
+ "svdvorak,dvorak-alt-intl",
+ NULL,
+ NULL,
+ NULL);
+ done = FALSE;
+ meta_backend_set_keymap_async (backend, keymap_description2, 0,
+ NULL, set_keymap_expect_error_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert_true (keymap == meta_backend_get_keymap (backend));
+
+ /*
+ * Set the same keymap with a different layout index. Should take effect.
+ */
+
+ was_signalled = FALSE;
+ keymap_layout_group_changed_handler_id =
+ g_signal_connect_swapped (backend,
+ "keymap-layout-group-changed",
+ G_CALLBACK (set_true_cb),
+ &was_signalled);
+
+ done = FALSE;
+ meta_backend_set_keymap_async (backend, keymap_description1, 1,
+ NULL, set_keymap_layout_group_cb, &done);
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 1);
+ g_assert_true (was_signalled);
+
+ xkb_keymap_unref (keymap);
+ g_signal_handler_disconnect (backend, keymap_changed_handler_id);
+ g_signal_handler_disconnect (backend, keymap_layout_group_changed_handler_id);
+
+ /*
+ * Set another keymap with the same owner. Should take effect.
+ */
+
+ keymap_description3 =
+ meta_keymap_description_new_from_rules (NULL,
+ "ua",
+ "",
+ NULL,
+ NULL,
+ NULL);
+ meta_keymap_description_unlock (keymap_description3, owner);
+ done = FALSE;
+ meta_backend_set_keymap_async (backend, keymap_description3, 0,
+ NULL, set_keymap_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ keymap = meta_backend_get_keymap (backend);
+ g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 1);
+ g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
+ ==,
+ "Ukrainian");
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
+
+ /*
+ * Set keymap again without owner. Should take effect.
+ */
+
+ done = FALSE;
+ meta_backend_set_keymap_async (backend, keymap_description2, 0,
+ NULL, set_keymap_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ keymap = meta_backend_get_keymap (backend);
+ g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
+ g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
+ ==,
+ "Swedish (Svdvorak)");
+ g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 1),
+ ==,
+ "English (Dvorak, alt. intl.)");
+ g_assert_cmpuint (meta_backend_get_keymap_layout_group (backend), ==, 0);
+
+ meta_keymap_description_owner_unref (owner);
+}
+
static void
record_modifier_state (ClutterKeymap *keymap,
ModMaskTuple **expected_mods)
@@ -460,6 +623,8 @@ init_tests (void)
meta_test_native_keyboard_map_change_layout);
g_test_add_func ("/backends/native/keyboard-map/set-layout-index",
meta_test_native_keyboard_map_set_layout_index);
+ g_test_add_func ("/backends/native/keyboard-map/lock-layout",
+ meta_test_native_keyboard_map_lock_layout);
g_test_add_func ("/backends/native/keyboard-map/modifiers",
meta_test_native_keyboard_map_modifiers);
}
--
2.54.0
From c5d98a94b453b7b869f9d8cc7a818e9f9698f98e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Mon, 15 Dec 2025 21:32:31 +0100
Subject: [PATCH 24/32] backend: Only let owner reset keymap
This allows enforcing only the owner of a locked keymap description can
reset it to something else.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 097ad5b10695cd006e8e50b51df5d6cdcee83eb1)
---
src/backends/meta-backend-private.h | 12 +-
src/backends/meta-backend.c | 11 +-
.../meta-keymap-description-private.h | 5 +
src/backends/meta-keymap-description.c | 18 +++
src/backends/native/meta-seat-impl.c | 2 +
src/tests/keyboard-map-tests.c | 123 ++++++++++++++++++
6 files changed, 163 insertions(+), 8 deletions(-)
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index c82d41032d..8b61738922 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -34,6 +34,7 @@
#include "backends/meta-egl.h"
#include "backends/meta-input-mapper-private.h"
#include "backends/meta-input-settings-private.h"
+#include "backends/meta-keymap-description-private.h"
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-pointer-constraint.h"
#include "backends/meta-renderer.h"
@@ -213,14 +214,17 @@ struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
META_EXPORT_TEST
xkb_layout_index_t meta_backend_get_keymap_layout_group (MetaBackend *backend);
+META_EXPORT_TEST
gboolean meta_backend_reset_keymap_finish (MetaBackend *backend,
GAsyncResult *result,
GError **error);
-void meta_backend_reset_keymap_async (MetaBackend *backend,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+META_EXPORT_TEST
+void meta_backend_reset_keymap_async (MetaBackend *backend,
+ MetaKeymapDescriptionOwner *owner,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
gboolean meta_backend_is_lid_closed (MetaBackend *backend);
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 03ebf27ee4..143797213d 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -1851,10 +1851,11 @@ meta_backend_reset_keymap_finish (MetaBackend *backend,
}
void
-meta_backend_reset_keymap_async (MetaBackend *backend,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+meta_backend_reset_keymap_async (MetaBackend *backend,
+ MetaKeymapDescriptionOwner *owner,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
g_autoptr (MetaKeymapDescription) keymap_description = NULL;
uint32_t layout_index = 0;
@@ -1881,6 +1882,8 @@ meta_backend_reset_keymap_async (MetaBackend *backend,
layout_index = 0;
}
+ meta_keymap_description_reset_owner (keymap_description, owner);
+
task = g_task_new (G_OBJECT (backend), cancellable, callback, user_data);
g_task_set_source_tag (task, meta_backend_reset_keymap_async);
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index 5bf0b25505..f53092cd27 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -57,4 +57,9 @@ META_EXPORT_TEST
void meta_keymap_description_unlock (MetaKeymapDescription *keymap_description,
MetaKeymapDescriptionOwner *owner);
+void meta_keymap_description_reset_owner (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescriptionOwner *owner);
+
MetaKeymapDescriptionOwner * meta_keymap_description_get_owner (MetaKeymapDescription *keymap_description);
+
+MetaKeymapDescriptionOwner * meta_keymap_description_resets_owner (MetaKeymapDescription *keymap_description);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index b67bcf0a74..60a06fc5da 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -39,6 +39,7 @@ struct _MetaKeymapDescription
gboolean is_locked;
MetaKeymapDescriptionOwner *owner;
+ MetaKeymapDescriptionOwner *resets_owner;
union {
struct {
@@ -163,6 +164,8 @@ meta_keymap_description_unref (MetaKeymapDescription *keymap_description)
g_clear_pointer (&keymap_description->owner,
meta_keymap_description_owner_unref);
+ g_clear_pointer (&keymap_description->resets_owner,
+ meta_keymap_description_owner_unref);
g_free (keymap_description);
}
@@ -350,6 +353,15 @@ meta_keymap_description_unlock (MetaKeymapDescription *keymap_description,
keymap_description->owner = meta_keymap_description_owner_ref (owner);
}
+void
+meta_keymap_description_reset_owner (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescriptionOwner *owner)
+{
+ g_clear_pointer (&keymap_description->resets_owner,
+ meta_keymap_description_owner_unref);
+ keymap_description->resets_owner = meta_keymap_description_owner_ref (owner);
+}
+
gboolean
meta_keymap_description_is_locked (MetaKeymapDescription *keymap_description)
{
@@ -361,3 +373,9 @@ meta_keymap_description_get_owner (MetaKeymapDescription *keymap_description)
{
return keymap_description->owner;
}
+
+MetaKeymapDescriptionOwner *
+meta_keymap_description_resets_owner (MetaKeymapDescription *keymap_description)
+{
+ return keymap_description->resets_owner;
+}
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index ab8e207d16..2926bab779 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3902,6 +3902,8 @@ set_keyboard_map (GTask *task)
{
if (meta_keymap_description_is_locked (priv->keymap_description) &&
meta_keymap_description_get_owner (keymap_description) !=
+ meta_keymap_description_get_owner (priv->keymap_description) &&
+ meta_keymap_description_resets_owner (keymap_description) !=
meta_keymap_description_get_owner (priv->keymap_description))
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index 1bbb87430b..c705562736 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -72,6 +72,36 @@ set_keymap_expect_error_cb (GObject *source_object,
*done = TRUE;
}
+static void
+reset_keymap_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaBackend *backend = META_BACKEND (source_object);
+ gboolean *done = user_data;
+ g_autoptr (GError) error = NULL;
+
+ g_assert_true (meta_backend_reset_keymap_finish (backend, result, &error));
+ g_assert_no_error (error);
+
+ *done = TRUE;
+}
+
+static void
+reset_keymap_expect_error_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaBackend *backend = META_BACKEND (source_object);
+ gboolean *done = user_data;
+ g_autoptr (GError) error = NULL;
+
+ g_assert_false (meta_backend_reset_keymap_finish (backend, result, &error));
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+
+ *done = TRUE;
+}
+
static void
await_mod_mask (MetaKeymapNative *keymap_native,
ModMaskTuple **awaited_mod_mask)
@@ -504,6 +534,97 @@ meta_test_native_keyboard_map_lock_layout (void)
meta_keymap_description_owner_unref (owner);
}
+static MetaKeymapDescription *
+on_reset_keymap_description (MetaBackend *backend,
+ MetaKeymapDescription *keymap_description)
+{
+ return meta_keymap_description_ref (keymap_description);
+}
+
+static void
+meta_test_native_keyboard_map_lock_layout_reset (void)
+{
+ MetaBackend *backend = meta_context_get_backend (test_context);
+ g_autoptr (MetaKeymapDescription) keymap_description1 = NULL;
+ g_autoptr (MetaKeymapDescription) keymap_description2 = NULL;
+ MetaKeymapDescriptionOwner *owner;
+ MetaKeymapDescriptionOwner *other_owner;
+ gboolean done = FALSE;
+ gboolean was_signalled = FALSE;
+ gulong keymap_changed_handler_id;
+ gulong reset_keymap_handler_id;
+
+ owner = meta_keymap_description_owner_new ();
+ other_owner = meta_keymap_description_owner_new ();
+
+ keymap_description1 =
+ meta_keymap_description_new_from_rules (NULL,
+ "us,se",
+ "dvorak-alt-intl,svdvorak",
+ NULL,
+ NULL,
+ NULL);
+ meta_keymap_description_lock (keymap_description1, owner);
+ meta_backend_set_keymap_async (backend, keymap_description1, 0,
+ NULL, set_keymap_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ keymap_changed_handler_id =
+ g_signal_connect_swapped (backend,
+ "keymap-changed",
+ G_CALLBACK (trigger_error),
+ (gpointer) "Unexpected keymap-changed emission");
+
+ keymap_description2 =
+ meta_keymap_description_new_from_rules (NULL,
+ "se,us",
+ "svdvorak,dvorak-alt-intl",
+ NULL,
+ NULL,
+ NULL);
+ done = FALSE;
+ meta_backend_set_keymap_async (backend, keymap_description2, 0,
+ NULL, set_keymap_expect_error_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ reset_keymap_handler_id =
+ g_signal_connect (backend,
+ "reset-keymap-description",
+ G_CALLBACK (on_reset_keymap_description),
+ keymap_description2);
+
+ done = FALSE;
+ meta_backend_reset_keymap_async (backend, other_owner,
+ NULL, reset_keymap_expect_error_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ g_signal_handler_disconnect (backend, keymap_changed_handler_id);
+ keymap_changed_handler_id =
+ g_signal_connect_swapped (backend,
+ "keymap-changed",
+ G_CALLBACK (set_true_cb),
+ &was_signalled);
+
+ done = FALSE;
+ meta_backend_reset_keymap_async (backend, owner,
+ NULL, reset_keymap_cb, &done);
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert_true (meta_backend_get_keymap_description (backend) ==
+ keymap_description2);
+
+ g_assert_true (was_signalled);
+
+ g_signal_handler_disconnect (backend, keymap_changed_handler_id);
+ g_signal_handler_disconnect (backend, reset_keymap_handler_id);
+ meta_keymap_description_owner_unref (owner);
+ meta_keymap_description_owner_unref (other_owner);
+}
+
static void
record_modifier_state (ClutterKeymap *keymap,
ModMaskTuple **expected_mods)
@@ -625,6 +746,8 @@ init_tests (void)
meta_test_native_keyboard_map_set_layout_index);
g_test_add_func ("/backends/native/keyboard-map/lock-layout",
meta_test_native_keyboard_map_lock_layout);
+ g_test_add_func ("/backends/native/keyboard-map/lock-layout-reset",
+ meta_test_native_keyboard_map_lock_layout_reset);
g_test_add_func ("/backends/native/keyboard-map/modifiers",
meta_test_native_keyboard_map_modifiers);
}
--
2.54.0
From d62e2aec5b902aa180b3d825bc6348d388b62ce2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Thu, 2 Oct 2025 11:34:12 +0200
Subject: [PATCH 25/32] remote-desktop: Allow remote desktop servers to set the
keyboard layout
This allows remote desktop servers to take control of the keyboard
layout by setting their own keymap. This is meant to for example allow
using the same keymap in the remote system as in the system where the
remote desktop client is running.
For the time being, if the remote desktop server sets the keymap with a
'locked' property, it currently breaks the usage of input methods, as
they currently set what keyboard layout they work with, meaning that if
they can't override the keyboard layout, they wont work. This is a known
issue and deliberately not solved right now.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 0b8fae63112331043223f9aa6b234f4a99cd59b0)
---
.../org.gnome.Mutter.RemoteDesktop.xml | 100 ++++++
src/backends/meta-remote-desktop-session.c | 327 +++++++++++++++++-
2 files changed, 426 insertions(+), 1 deletion(-)
diff --git a/data/dbus-interfaces/org.gnome.Mutter.RemoteDesktop.xml b/data/dbus-interfaces/org.gnome.Mutter.RemoteDesktop.xml
index 815b1a3625..85cec80a9a 100644
--- a/data/dbus-interfaces/org.gnome.Mutter.RemoteDesktop.xml
+++ b/data/dbus-interfaces/org.gnome.Mutter.RemoteDesktop.xml
@@ -367,6 +367,106 @@
<arg type="h" name="fd" direction="out"/>
</method>
+ <!--
+ KeymapCapabilities:
+
+ Available options:
+
+ * ``supported-keymap-types`` (``au``)
+
+ Supported keymap types.
+
+ Available types:
+ ``0``: XKB: A keymap specified as a XKB keymap.
+
+ * ``supported-xkb-keymap-formats`` (``au``)
+
+ Supported XKB keymap formats.
+
+ Available formats:
+ ``1``: XKB_TEXT_V1: XKB text format version 1.
+ ``2``: XKB_TEXT_V2: XKB text format version 2.
+
+ -->
+ <property name="KeymapCapabilities" type="a{sv}" access="read"/>
+
+ <!--
+ SetKeymap:
+ @options: Options vararg describing the keymap.
+
+ Set the current input source. The type indicates how the input source is
+ defined.
+
+ For possible types, see the ``type`` option in KeyboardLayouts.
+
+ Available options:
+
+ * ``keymap-type`` (``u``)
+
+ The keymap type. Must only use a format listed in
+ ``supported-keymap-types`` in ``KeymapCapabilities``. Not setting the
+ keymap type resets the current keymap according to display server
+ policy.
+
+ * ``xkb-keymap-format`` (``u``)
+
+ The XKB keymap format. Must only use a format listed in
+ ``supported-xkb-keymap-formats``` in ``KeymapCapabilites``.
+
+ * ``xkb-keymap`` (``h``)
+
+ The XKB keymap in the XKB text format version 1. Required when setting
+ input source with ``XKB``.
+
+ * ``xkb-keymap-layout-index`` (``u``)
+
+ The initial XKB layout index.
+
+ * ``lock-keymap`` (``b``)
+
+ Lock the keymap to the specified one. This will result in the
+ keymap not being changable via the regular methods normally
+ used within the remote system.
+
+ Defaults to false.
+
+ -->
+ <method name="SetKeymap">
+ <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
+ <arg name="options" type="a{sv}" direction="in"/>
+ </method>
+
+ <!--
+ SetKeymapLayoutIndex:
+ @index: The layout index
+
+ Sets the layout group index in the keymap set via SetKeymap. Will only
+ succeed if the current keymap is one set by the last call to SetKeymap
+ on this session.
+ -->
+ <method name="SetKeymapLayoutIndex">
+ <arg name="index" type="u" direction="in"/>
+ </method>
+
+ <!--
+ CurrentKeymap:
+
+ Available options:
+
+ * ``name`` (``s``)
+
+ The name of the current active keymap.
+
+ * ``source`` (``u``)
+
+ The source of the current active keymap.
+
+ Available sources:
+ ``0``: EXTERNAL: Keymap was configured externally to this session.
+ ``1``: SESSION: Keymap was configured by this session.
+ -->
+ <property name="CurrentKeymap" type="a{sv}" access="read"/>
+
</interface>
</node>
diff --git a/src/backends/meta-remote-desktop-session.c b/src/backends/meta-remote-desktop-session.c
index bda50e3110..82591bd9e7 100644
--- a/src/backends/meta-remote-desktop-session.c
+++ b/src/backends/meta-remote-desktop-session.c
@@ -31,17 +31,19 @@
#include <unistd.h>
#include <xkbcommon/xkbcommon.h>
+#include "backends/meta-backend-private.h"
#include "backends/meta-dbus-session-watcher.h"
#include "backends/meta-dbus-session-manager.h"
#include "backends/meta-eis.h"
+#include "backends/meta-keymap-description-private.h"
#include "backends/meta-logical-monitor-private.h"
#include "backends/meta-screen-cast-session.h"
#include "backends/meta-remote-access-controller-private.h"
#include "cogl/cogl.h"
#include "core/display-private.h"
+#include "core/meta-sealed-fd.h"
#include "core/meta-selection-private.h"
#include "core/meta-selection-source-remote.h"
-#include "meta/meta-backend.h"
#include "meta-dbus-remote-desktop.h"
@@ -49,6 +51,20 @@
#define TRANSFER_REQUEST_CLEANUP_TIMEOUT_MS (s2ms (15))
+typedef enum _MetaRemoteDesktopKeymapFormat
+{
+ META_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_V1 = 1,
+ META_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_V2 = 2,
+} MetaRemoteDesktopKeymapFormat;
+
+typedef enum _MetaRemoteDesktopKeymapSource
+{
+ META_REMOTE_DESKTOP_KEYMAP_SOURCE_EXTERNAL = 0,
+ META_REMOTE_DESKTOP_KEYMAP_SOURCE_SESSION = 1,
+} MetaRemoteDesktopKeymapSource;
+
+#define SUPPORTED_KEYMAP_FORMATS (1 << META_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_V1)
+
enum
{
PROP_0,
@@ -106,6 +122,14 @@ struct _MetaRemoteDesktopSession
GHashTable *mapping_ids;
gulong monitors_changed_handler_id;
+ gulong keymap_changed_handler_id;
+ gulong keymap_layout_group_changed_handler_id;
+ gulong keymap_state_changed_handler_id;
+
+ MetaKeymapDescription *keymap_description;
+ MetaKeymapDescriptionOwner *keymap_owner;
+
+ GCancellable *cancellable;
};
static void initable_init_iface (GInitableIface *iface);
@@ -475,6 +499,8 @@ meta_remote_desktop_session_close (MetaDbusSession *dbus_session)
meta_dbus_session_manager_get_backend (session->session_manager);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
+ ClutterSeat *seat = meta_backend_get_default_seat (backend);
+ ClutterKeymap *keymap = clutter_seat_get_keymap (seat);
session->started = FALSE;
@@ -491,6 +517,12 @@ meta_remote_desktop_session_close (MetaDbusSession *dbus_session)
g_clear_signal_handler (&session->monitors_changed_handler_id,
monitor_manager);
+ g_clear_signal_handler (&session->keymap_changed_handler_id,
+ backend);
+ g_clear_signal_handler (&session->keymap_layout_group_changed_handler_id,
+ backend);
+ g_clear_signal_handler (&session->keymap_state_changed_handler_id,
+ keymap);
g_clear_object (&session->virtual_pointer);
g_clear_object (&session->virtual_keyboard);
@@ -1998,6 +2030,276 @@ handle_connect_to_eis (MetaDBusRemoteDesktopSession *skeleton,
return G_DBUS_METHOD_INVOCATION_HANDLED;
}
+static void
+update_current_keymap (MetaRemoteDesktopSession *session)
+{
+ MetaBackend *backend =
+ meta_dbus_session_manager_get_backend (session->session_manager);
+ ClutterSeat *seat = meta_backend_get_default_seat (backend);
+ ClutterKeymap *keymap;
+ MetaKeymapDescription *keymap_description;
+ GVariantBuilder builder;
+ const char *layout_name;
+ MetaRemoteDesktopKeymapSource source;
+
+ keymap = clutter_seat_get_keymap (seat);
+ keymap_description = meta_backend_get_keymap_description (backend);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ layout_name = clutter_keymap_get_current_display_name (keymap);
+ if (layout_name)
+ {
+ g_variant_builder_add (&builder, "{sv}",
+ "name", g_variant_new_string (layout_name));
+ }
+
+ if (keymap_description == session->keymap_description)
+ source = META_REMOTE_DESKTOP_KEYMAP_SOURCE_SESSION;
+ else
+ source = META_REMOTE_DESKTOP_KEYMAP_SOURCE_EXTERNAL;
+ g_variant_builder_add (&builder, "{sv}",
+ "source", g_variant_new_uint32 (source));
+
+ meta_dbus_remote_desktop_session_set_current_keymap (
+ META_DBUS_REMOTE_DESKTOP_SESSION (session),
+ g_variant_builder_end (&builder));
+}
+
+typedef struct _SetKeymapData
+{
+ MetaRemoteDesktopSession *session;
+ GDBusMethodInvocation *invocation;
+} SetKeymapData;
+
+static void
+set_keymap_data_free (gpointer user_data)
+{
+ SetKeymapData *data = user_data;
+
+ g_free (data);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SetKeymapData, set_keymap_data_free)
+
+static void
+set_keymap_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaBackend *backend = META_BACKEND (source_object);
+ g_autoptr (SetKeymapData) data = user_data;
+ MetaRemoteDesktopSession *session = data->session;
+ g_autoptr (GError) error = NULL;
+
+ if (!meta_backend_set_keymap_finish (backend, result, &error))
+ {
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
+ return;
+ }
+
+ meta_dbus_remote_desktop_session_complete_set_keymap (
+ META_DBUS_REMOTE_DESKTOP_SESSION (session),
+ data->invocation,
+ NULL);
+
+ update_current_keymap (session);
+}
+
+static void
+reset_keymap_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaBackend *backend = META_BACKEND (source_object);
+ g_autoptr (SetKeymapData) data = user_data;
+ MetaRemoteDesktopSession *session = data->session;
+ g_autoptr (GError) error = NULL;
+
+ if (!meta_backend_reset_keymap_finish (backend, result, &error))
+ {
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
+ return;
+ }
+
+ g_clear_pointer (&session->keymap_description,
+ meta_keymap_description_unref);
+
+ meta_dbus_remote_desktop_session_complete_set_keymap (
+ META_DBUS_REMOTE_DESKTOP_SESSION (session),
+ data->invocation,
+ NULL);
+
+ update_current_keymap (session);
+}
+
+static gboolean
+verify_keymap_format (uint32_t keymap_format)
+{
+ switch (keymap_format)
+ {
+ case META_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_V1:
+ case META_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_V2:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+handle_set_keymap (MetaDBusRemoteDesktopSession *skeleton,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list_in,
+ GVariant *arg_options)
+{
+ MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
+ MetaBackend *backend =
+ meta_dbus_session_manager_get_backend (session->session_manager);
+ uint32_t keymap_type = UINT32_MAX;
+ uint32_t keymap_format = UINT32_MAX;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GVariant) keymap_handle = NULL;
+ g_autoptr (MetaSealedFd) sealed_keymap = NULL;
+ g_autoptr (MetaKeymapDescription) keymap_description = NULL;
+ uint32_t layout_index = 0;
+ gboolean lock_keymap;
+ SetKeymapData *data;
+
+ if (!g_variant_lookup (arg_options, "keymap-type", "u", &keymap_type))
+ {
+ data = g_new0 (SetKeymapData, 1);
+ data->session = session;
+ data->invocation = invocation;
+
+ meta_backend_reset_keymap_async (backend,
+ session->keymap_owner,
+ session->cancellable,
+ reset_keymap_cb,
+ data);
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ g_variant_lookup (arg_options, "xkb-keymap-format", "u", &keymap_format);
+
+ if (!verify_keymap_format (keymap_format))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid keymap format");
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ if (!((1 << keymap_format) & SUPPORTED_KEYMAP_FORMATS))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Non-supported keymap format");
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ keymap_handle = g_variant_lookup_value (arg_options, "xkb-keymap",
+ G_VARIANT_TYPE_HANDLE);
+ if (!keymap_handle)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "No keymap handle");
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ sealed_keymap = meta_sealed_fd_new_from_handle (keymap_handle,
+ fd_list_in,
+ &error);
+
+ g_variant_lookup (arg_options, "xkb-keymap-layout-index", "u", &layout_index);
+
+ keymap_description = meta_keymap_description_new_from_fd (sealed_keymap,
+ keymap_format);
+ if (g_variant_lookup (arg_options, "lock-keymap", "b", &lock_keymap) &&
+ lock_keymap)
+ meta_keymap_description_lock (keymap_description, session->keymap_owner);
+ else
+ meta_keymap_description_unlock (keymap_description, session->keymap_owner);
+
+ data = g_new0 (SetKeymapData, 1);
+ data->session = session;
+ data->invocation = invocation;
+
+ g_clear_pointer (&session->keymap_description,
+ meta_keymap_description_unref);
+ session->keymap_description =
+ meta_keymap_description_ref (keymap_description);
+
+ meta_backend_set_keymap_async (backend,
+ keymap_description,
+ layout_index,
+ session->cancellable,
+ set_keymap_cb,
+ data);
+
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+
+}
+
+static void
+set_keymap_layout_group_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaBackend *backend = META_BACKEND (source_object);
+ g_autoptr (SetKeymapData) data = user_data;
+ g_autoptr (GError) error = NULL;
+
+ if (!meta_backend_set_keymap_finish (backend, result, &error))
+ {
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
+ return;
+ }
+
+ meta_dbus_remote_desktop_session_complete_set_keymap_layout_index (
+ META_DBUS_REMOTE_DESKTOP_SESSION (data->session),
+ data->invocation);
+}
+
+static gboolean
+handle_set_keymap_layout_index (MetaDBusRemoteDesktopSession *skeleton,
+ GDBusMethodInvocation *invocation,
+ uint32_t layout_index)
+{
+ MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
+ MetaBackend *backend =
+ meta_dbus_session_manager_get_backend (session->session_manager);
+ MetaKeymapDescription *keymap_description;
+ SetKeymapData *data;
+
+ keymap_description = meta_backend_get_keymap_description (backend);
+
+ if (!session->keymap_description ||
+ keymap_description != session->keymap_description)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Invalid current keymap");
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ data = g_new0 (SetKeymapData, 1);
+ data->session = session;
+ data->invocation = invocation;
+
+ meta_backend_set_keymap_async (backend,
+ session->keymap_description,
+ layout_index,
+ session->cancellable,
+ set_keymap_layout_group_cb,
+ data);
+
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+}
+
static gboolean
meta_remote_desktop_session_initable_init (GInitable *initable,
GCancellable *cancellable,
@@ -2029,6 +2331,17 @@ meta_remote_desktop_session_initable_init (GInitable *initable,
session, "num-lock-state",
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+ session->keymap_changed_handler_id =
+ g_signal_connect_swapped (backend, "keymap-changed",
+ G_CALLBACK (update_current_keymap), session);
+ session->keymap_layout_group_changed_handler_id =
+ g_signal_connect_swapped (backend, "keymap-layout-group-changed",
+ G_CALLBACK (update_current_keymap), session);
+ session->keymap_state_changed_handler_id =
+ g_signal_connect_swapped (keymap, "state-changed",
+ G_CALLBACK (update_current_keymap), session);
+ update_current_keymap (session);
+
session->mapping_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
return TRUE;
@@ -2062,6 +2375,8 @@ meta_remote_desktop_session_init_iface (MetaDBusRemoteDesktopSessionIface *iface
iface->handle_selection_write_done = handle_selection_write_done;
iface->handle_selection_read = handle_selection_read;
iface->handle_connect_to_eis = handle_connect_to_eis;
+ iface->handle_set_keymap = handle_set_keymap;
+ iface->handle_set_keymap_layout_index = handle_set_keymap_layout_index;
}
static void
@@ -2079,6 +2394,9 @@ meta_remote_desktop_session_finalize (GObject *object)
g_assert (!meta_remote_desktop_session_is_running (session));
+ g_cancellable_cancel (session->cancellable);
+ g_clear_object (&session->cancellable);
+
g_clear_signal_handler (&session->owner_changed_handler_id, selection);
reset_current_selection_source (session);
cancel_selection_read (session);
@@ -2086,6 +2404,9 @@ meta_remote_desktop_session_finalize (GObject *object)
g_clear_pointer (&session->mapping_ids, g_hash_table_unref);
+ g_clear_pointer (&session->keymap_description, meta_keymap_description_unref);
+ g_clear_pointer (&session->keymap_owner, meta_keymap_description_owner_unref);
+
g_clear_object (&session->handle);
g_free (session->peer_name);
g_free (session->session_id);
@@ -2154,6 +2475,10 @@ meta_remote_desktop_session_init (MetaRemoteDesktopSession *session)
++global_session_number);
session->transfer_requests = g_hash_table_new (NULL, NULL);
+
+ session->keymap_owner = meta_keymap_description_owner_new ();
+
+ session->cancellable = g_cancellable_new ();
}
static void
--
2.54.0
From ec2bd8948e1014325f1c4e247863289666f33d7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Mon, 29 Sep 2025 16:36:43 +0200
Subject: [PATCH 26/32] mdk: Allow mirroring the host keymap in the nested
instance
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 5a78b12a3579b8c30a43a60f3f344f142db2626c)
---
mdk/mdk-context.c | 19 +++++
mdk/mdk-context.h | 2 +
mdk/mdk-main-window.ui | 4 +
mdk/mdk-main.c | 3 +
mdk/mdk-session.c | 179 +++++++++++++++++++++++++++++++++++++++++
mdk/meson.build | 1 +
6 files changed, 208 insertions(+)
diff --git a/mdk/mdk-context.c b/mdk/mdk-context.c
index 38112ab0cb..a358719d53 100644
--- a/mdk/mdk-context.c
+++ b/mdk/mdk-context.c
@@ -36,6 +36,7 @@ enum
PROP_EMULATE_TOUCH,
PROP_INHIBIT_SYSTEM_SHORTCUTS,
+ PROP_USE_HOST_KEYMAP,
N_PROPS
};
@@ -67,6 +68,7 @@ struct _MdkContext
gboolean emulate_touch;
gboolean inhibit_system_shortcuts;
+ gboolean use_host_keymap;
GSettings *settings;
@@ -324,6 +326,9 @@ mdk_context_set_property (GObject *object,
case PROP_INHIBIT_SYSTEM_SHORTCUTS:
context->inhibit_system_shortcuts = g_value_get_boolean (value);
break;
+ case PROP_USE_HOST_KEYMAP:
+ context->use_host_keymap = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -346,6 +351,9 @@ mdk_context_get_property (GObject *object,
case PROP_INHIBIT_SYSTEM_SHORTCUTS:
g_value_set_boolean (value, context->inhibit_system_shortcuts);
break;
+ case PROP_USE_HOST_KEYMAP:
+ g_value_set_boolean (value, context->use_host_keymap);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -386,6 +394,11 @@ mdk_context_class_init (MdkContextClass *klass)
FALSE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
+ obj_props[PROP_USE_HOST_KEYMAP] =
+ g_param_spec_boolean ("use-host-keymap", NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
signals[READY] = g_signal_new ("ready",
@@ -593,6 +606,12 @@ mdk_context_get_inhibit_system_shortcuts (MdkContext *context)
return context->inhibit_system_shortcuts;
}
+gboolean
+mdk_context_get_use_host_keymap (MdkContext *context)
+{
+ return context->use_host_keymap;
+}
+
GPtrArray *
mdk_context_get_launchers (MdkContext *context)
{
diff --git a/mdk/mdk-context.h b/mdk/mdk-context.h
index 29fb359741..e3f6a519b4 100644
--- a/mdk/mdk-context.h
+++ b/mdk/mdk-context.h
@@ -38,6 +38,8 @@ gboolean mdk_context_get_emulate_touch (MdkContext *context);
gboolean mdk_context_get_inhibit_system_shortcuts (MdkContext *context);
+gboolean mdk_context_get_use_host_keymap (MdkContext *context);
+
GPtrArray * mdk_context_get_launchers (MdkContext *context);
void mdk_context_activate_launcher (MdkContext *context,
diff --git a/mdk/mdk-main-window.ui b/mdk/mdk-main-window.ui
index b420aa7bd2..a431770366 100644
--- a/mdk/mdk-main-window.ui
+++ b/mdk/mdk-main-window.ui
@@ -13,6 +13,10 @@
<attribute name="label" translatable="yes">_Inhibit system shortcuts</attribute>
<attribute name="action">app.toggle_inhibit_system_shortcuts</attribute>
</item>
+ <item>
+ <attribute name="label" translatable="yes">Use host _keymap</attribute>
+ <attribute name="action">app.toggle_host_keymap</attribute>
+ </item>
</submenu>
</section>
<section>
diff --git a/mdk/mdk-main.c b/mdk/mdk-main.c
index 8e61373616..ff37dad4a2 100644
--- a/mdk/mdk-main.c
+++ b/mdk/mdk-main.c
@@ -237,6 +237,7 @@ main (int argc,
{ "about", activate_about, NULL, NULL, NULL },
{ "toggle_emulate_touch", .state = "false", },
{ "toggle_inhibit_system_shortcuts", .state = "false", },
+ { "toggle_host_keymap", .state = "false", },
{ "launch", activate_launch, .parameter_type = "i", },
{ "edit_launchers", activate_edit_launchers, },
};
@@ -257,6 +258,8 @@ main (int argc,
app->context, "emulate-touch");
bind_action_to_property (app, "toggle_inhibit_system_shortcuts",
app->context, "inhibit-system-shortcuts");
+ bind_action_to_property (app, "toggle_host_keymap",
+ app->context, "use-host-keymap");
g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
diff --git a/mdk/mdk-session.c b/mdk/mdk-session.c
index 43793c8fc5..239d5dacd9 100644
--- a/mdk/mdk-session.c
+++ b/mdk/mdk-session.c
@@ -19,10 +19,13 @@
#include "mdk-session.h"
+#include <gdk/wayland/gdkwayland.h>
#include <gio/gio.h>
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <libei.h>
+#include <sys/mman.h>
+#include <xkbcommon/xkbcommon.h>
#include "mdk-context.h"
#include "mdk-ei.h"
@@ -41,6 +44,17 @@ typedef enum _MdkScreenCastCursorMode
MDK_SCREEN_CAST_CURSOR_MODE_METADATA = 2,
} MdkScreenCastCursorMode;
+typedef enum _MdkRemoteDesktopKeymapType
+{
+ MDK_REMOTE_DESKTOP_KEYMAP_TYPE_XKB = 0,
+} MdkRemoteDesktopKeymapType;
+
+typedef enum _MdkRemoteDesktopKeymapFormat
+{
+ MDK_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_TEXT_V1 = 1,
+ MDK_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_TEXT_V2 = 2,
+} MdkRemoteDesktopKeymapFormat;
+
enum
{
PROP_0,
@@ -73,6 +87,9 @@ struct _MdkSession
MdkDBusScreenCast *screen_cast_proxy;
MdkDBusRemoteDesktopSession *remote_desktop_session_proxy;
MdkDBusScreenCastSession *screen_cast_session_proxy;
+
+ struct xkb_keymap *xkb_keymap;
+ int layout_index;
};
static void
@@ -89,6 +106,150 @@ on_session_closed (MdkDBusRemoteDesktopSession *remote_desktop_session_proxy,
g_signal_emit (session, signals[CLOSED], 0);
}
+static void
+maybe_sync_keymap (MdkSession *session)
+{
+ GdkDisplay *display = gdk_display_get_default ();
+ GdkSeat *seat = gdk_display_get_default_seat (display);
+ GdkDevice *keyboard = gdk_seat_get_keyboard (seat);
+ struct xkb_keymap *xkb_keymap;
+ int layout_index;
+
+ if (!mdk_context_get_use_host_keymap (session->context))
+ {
+ if (session->xkb_keymap)
+ {
+ GVariantBuilder options_builder;
+
+ session->xkb_keymap = NULL;
+
+ g_variant_builder_init (&options_builder, G_VARIANT_TYPE ("a{sv}"));
+ mdk_dbus_remote_desktop_session_call_set_keymap (
+ session->remote_desktop_session_proxy,
+ g_variant_builder_end (&options_builder),
+ NULL,
+ NULL, NULL, NULL);
+ }
+ return;
+ }
+
+ if (!GDK_IS_WAYLAND_DISPLAY (display))
+ {
+ g_warning ("Changing keymap not supported when running from X11");
+ return;
+ }
+
+ xkb_keymap = gdk_wayland_device_get_xkb_keymap (keyboard);
+ layout_index = gdk_device_get_active_layout_index (keyboard);
+
+ if (xkb_keymap == session->xkb_keymap &&
+ layout_index == session->layout_index)
+ return;
+
+ session->layout_index = layout_index;
+
+ if (xkb_keymap != session->xkb_keymap)
+ {
+ g_autofree char *keymap_serialized = NULL;
+ g_autofd int fd = -1;
+ int fd_idx;
+ size_t keymap_size;
+ void *keymap_mem;
+ GVariantBuilder options_builder;
+ g_autoptr (GUnixFDList) fd_list = NULL;
+ g_autoptr (GError) error = NULL;
+
+ session->xkb_keymap = xkb_keymap;
+
+ keymap_serialized = xkb_keymap_get_as_string (xkb_keymap,
+ XKB_KEYMAP_FORMAT_TEXT_V1);
+ if (!keymap_serialized)
+ {
+ g_warning ("Failed to serialize current keymap.");
+ return;
+ }
+
+ fd = memfd_create ("mdk-keymap", MFD_ALLOW_SEALING | MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ g_warning ("Failed to create keymap memfd: %s", g_strerror (errno));
+ return;
+ }
+
+ keymap_size = strlen (keymap_serialized) + 1;
+ if (ftruncate (fd, keymap_size) == -1)
+ {
+ g_warning ("ftruncate of keymap fd failed: %s", g_strerror (errno));
+ return;
+ }
+
+ keymap_mem = mmap (NULL, keymap_size, PROT_WRITE, MAP_SHARED, fd, 0);
+ if (keymap_mem == MAP_FAILED)
+ {
+ g_warning ("Failed mmap keymap fd: %s", g_strerror (errno));
+ return;
+ }
+
+ strcpy (keymap_mem, keymap_serialized);
+
+ if (munmap (keymap_mem, keymap_size) == -1)
+ {
+ g_warning ("Failed munmap keymap fd: %s", g_strerror (errno));
+ return;
+ }
+
+ fd_list = g_unix_fd_list_new ();
+
+ fd_idx = g_unix_fd_list_append (fd_list, fd, &error);
+ if (fd_idx == -1)
+ {
+ g_warning ("Failed to append file descriptor to fd list: %s",
+ error->message);
+ return;
+ }
+
+ layout_index = gdk_device_get_active_layout_index (keyboard);
+
+ g_variant_builder_init (&options_builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&options_builder, "{sv}",
+ "keymap-type",
+ g_variant_new_uint32 (MDK_REMOTE_DESKTOP_KEYMAP_TYPE_XKB));
+ g_variant_builder_add (&options_builder, "{sv}",
+ "xkb-keymap-format",
+ g_variant_new_uint32 (MDK_REMOTE_DESKTOP_KEYMAP_FORMAT_XKB_TEXT_V1));
+ g_variant_builder_add (&options_builder, "{sv}",
+ "xkb-keymap",
+ g_variant_new_handle (fd_idx));
+ g_variant_builder_add (&options_builder, "{sv}",
+ "xkb-keymap-layout-index",
+ g_variant_new_uint32 (layout_index));
+ g_variant_builder_add (&options_builder, "{sv}",
+ "lock-keymap",
+ g_variant_new_boolean (TRUE));
+
+ mdk_dbus_remote_desktop_session_call_set_keymap (
+ session->remote_desktop_session_proxy,
+ g_variant_builder_end (&options_builder),
+ fd_list,
+ NULL, NULL, NULL);
+ }
+ else
+ {
+ mdk_dbus_remote_desktop_session_call_set_keymap_layout_index (
+ session->remote_desktop_session_proxy,
+ layout_index,
+ NULL, NULL, NULL);
+ }
+}
+
+static void
+on_use_host_keymap_changed (MdkContext *context,
+ GParamSpec *pspec,
+ MdkSession *session)
+{
+ maybe_sync_keymap (session);
+}
+
static gboolean
init_session (MdkSession *session,
GCancellable *cancellable,
@@ -187,6 +348,12 @@ init_session (MdkSession *session,
G_CALLBACK (on_session_closed),
session);
+ g_signal_connect_object (session->context,
+ "notify::use-host-keymap",
+ G_CALLBACK (on_use_host_keymap_changed),
+ session,
+ G_CONNECT_DEFAULT);
+
return TRUE;
}
@@ -196,6 +363,9 @@ mdk_session_initable_init (GInitable *initable,
GError **error)
{
MdkSession *session = MDK_SESSION (initable);
+ GdkDisplay *display = gdk_display_get_default ();
+ GdkSeat *seat = gdk_display_get_default_seat (display);
+ GdkDevice *keyboard = gdk_seat_get_keyboard (seat);
g_debug ("Initializing session");
@@ -230,6 +400,15 @@ mdk_session_initable_init (GInitable *initable,
error))
return FALSE;
+ g_signal_connect_object (keyboard, "notify::layout-names",
+ G_CALLBACK (maybe_sync_keymap),
+ session,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (keyboard, "notify::active-layout-index",
+ G_CALLBACK (maybe_sync_keymap),
+ session,
+ G_CONNECT_SWAPPED);
+
return TRUE;
}
diff --git a/mdk/meson.build b/mdk/meson.build
index d3e4184ca4..59a39b9c57 100644
--- a/mdk/meson.build
+++ b/mdk/meson.build
@@ -91,6 +91,7 @@ executable('mutter-devkit',
libpipewire_dep,
libdrm_dep,
libei_dep,
+ xkbcommon_dep,
],
install_dir: libexecdir,
install: true,
--
2.54.0
From fc4743e8812280b181ff3097b37ad619c431d24d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Fri, 3 Oct 2025 15:41:09 +0200
Subject: [PATCH 27/32] keymap-description: Add 'direct_equal()' API
This is meant to be used by Javascript via GI to check whether one
instance is exactly the same as another, to effectively check if was one
self that set the keymap description in question.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 3e458cc611026bd4095012c488584b612b85ea4b)
---
src/backends/meta-keymap-description.c | 7 +++++++
src/meta/meta-keymap-description.h | 4 ++++
2 files changed, 11 insertions(+)
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index 60a06fc5da..4d077626df 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -177,6 +177,13 @@ meta_keymap_description_get_source (MetaKeymapDescription *keymap_description)
return keymap_description->source;
}
+gboolean
+meta_keymap_description_direct_equal (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescription *other)
+{
+ return keymap_description == other;
+}
+
static char *
maybe_derive_short_name (struct rxkb_context *rxkb_context,
const char *layout_name)
diff --git a/src/meta/meta-keymap-description.h b/src/meta/meta-keymap-description.h
index 0f4de5ed2b..d4f9431ef8 100644
--- a/src/meta/meta-keymap-description.h
+++ b/src/meta/meta-keymap-description.h
@@ -45,5 +45,9 @@ void meta_keymap_description_unref (MetaKeymapDescription *keymap_description);
META_EXPORT
gboolean meta_keymap_description_is_locked (MetaKeymapDescription *keymap_description);
+META_EXPORT
+gboolean meta_keymap_description_direct_equal (MetaKeymapDescription *keymap_description,
+ MetaKeymapDescription *other);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKeymapDescription,
meta_keymap_description_unref);
--
2.54.0
From f2c21f79e5587ad1c204dad787bb3de7bd0ba7d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Fri, 3 Oct 2025 15:42:19 +0200
Subject: [PATCH 28/32] tests/keyboard-map-tests: Assert keymap description
sanity on signal
When signalled that the keymap changed, make sure the currently returned
keymap description is the one that was changed to.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 34f9765e27056ea90b800538c2d77189ece3e810)
---
src/tests/keyboard-map-tests.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index c705562736..a26b1a7bf4 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -150,6 +150,14 @@ on_keymap_changed (MetaBackend *backend,
*expected_next_handler = on_keymap_state_changed;
}
+static void
+on_keymap_changed2 (MetaBackend *backend,
+ MetaKeymapDescription *expected_keymap_description)
+{
+ g_assert_true (expected_keymap_description ==
+ meta_backend_get_keymap_description (backend));
+}
+
static void
meta_test_native_keyboard_map_set_async (void)
{
@@ -168,6 +176,7 @@ meta_test_native_keyboard_map_set_async (void)
gpointer expected_next_handler;
gulong await_mod_mask_handler_id;
gulong keymap_changed_handler_id;
+ gulong keymap_changed_handler_id2;
gulong keymap_state_changed_handler_id;
await_mod_mask_handler_id =
@@ -215,6 +224,13 @@ meta_test_native_keyboard_map_set_async (void)
NULL,
NULL,
NULL);
+
+ keymap_changed_handler_id2 =
+ g_signal_connect (backend,
+ "keymap-changed",
+ G_CALLBACK (on_keymap_changed2),
+ keymap_description);
+
meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
@@ -240,6 +256,7 @@ meta_test_native_keyboard_map_set_async (void)
meta_wait_for_update (test_context);
g_signal_handler_disconnect (backend, keymap_changed_handler_id);
+ g_signal_handler_disconnect (backend, keymap_changed_handler_id2);
g_signal_handler_disconnect (keymap, keymap_state_changed_handler_id);
}
--
2.54.0
From 2ed2a27f02aed240cc7791b7345d5b7fad5d770c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 28 Jan 2026 16:48:38 +0100
Subject: [PATCH 29/32] backend: Harmonize on keymap naming convention
Instead of sometimes calling it keyboard map or keymap, harmonize an
using the term keymap everywhere. One piece of API was renamed to
get_xkb_keymap() to distinguish between returning a ClutterKeymap, and a
xkb_keymap.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 2fe20346d03391412c37a54d687c9302eafa61ad)
---
src/backends/native/meta-backend-native.c | 24 +++---
.../native/meta-keymap-native-private.h | 16 ++--
src/backends/native/meta-keymap-native.c | 16 ++--
src/backends/native/meta-seat-impl.c | 50 +++++------
src/backends/native/meta-seat-impl.h | 20 ++---
src/backends/native/meta-seat-native.c | 84 +++++++++----------
src/backends/native/meta-seat-native.h | 22 ++---
.../native/meta-virtual-input-device-native.c | 3 +-
src/tests/keyboard-map-tests.c | 2 +-
9 files changed, 119 insertions(+), 118 deletions(-)
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 7d68894cb8..66105d6cb4 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -318,15 +318,15 @@ meta_backend_native_get_current_logical_monitor (MetaBackend *backend)
}
static void
-set_keyboard_map_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+set_keymap_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (source_object);
g_autoptr (GTask) task = G_TASK (user_data);
g_autoptr (GError) error = NULL;
- if (!meta_seat_native_set_keyboard_map_finish (seat_native, result, &error))
+ if (!meta_seat_native_set_keymap_finish (seat_native, result, &error))
{
g_task_return_error (task, g_steal_pointer (&error));
return;
@@ -345,12 +345,12 @@ meta_backend_native_set_keymap_async (MetaBackend *backend,
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
- meta_seat_native_set_keyboard_map_async (META_SEAT_NATIVE (seat),
- description,
- layout_index,
- g_task_get_cancellable (task),
- set_keyboard_map_cb,
- task);
+ meta_seat_native_set_keymap_async (META_SEAT_NATIVE (seat),
+ description,
+ layout_index,
+ g_task_get_cancellable (task),
+ set_keymap_cb,
+ task);
}
@@ -361,7 +361,7 @@ meta_backend_native_get_keymap (MetaBackend *backend)
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
- return meta_seat_native_get_keyboard_map (META_SEAT_NATIVE (seat));
+ return meta_seat_native_get_xkb_keymap (META_SEAT_NATIVE (seat));
}
static MetaKeymapDescription *
@@ -371,7 +371,7 @@ meta_backend_native_get_keymap_description (MetaBackend *backend)
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
- return meta_seat_native_get_keyboard_map_description (META_SEAT_NATIVE (seat));
+ return meta_seat_native_get_keymap_description (META_SEAT_NATIVE (seat));
}
static xkb_layout_index_t
diff --git a/src/backends/native/meta-keymap-native-private.h b/src/backends/native/meta-keymap-native-private.h
index e119b91c31..326451a282 100644
--- a/src/backends/native/meta-keymap-native-private.h
+++ b/src/backends/native/meta-keymap-native-private.h
@@ -25,15 +25,15 @@
#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h""
#endif /* META_INPUT_THREAD_H_INSIDE */
-void meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
- MetaSeatImpl *seat_impl,
- MetaKeymapDescription *keymap_description,
- struct xkb_keymap *xkb_keymap,
- struct xkb_state *xkb_state,
- GStrv display_names,
- GStrv short_names);
+void meta_keymap_native_set_keymap_in_impl (MetaKeymapNative *keymap,
+ MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ struct xkb_keymap *xkb_keymap,
+ struct xkb_state *xkb_state,
+ GStrv display_names,
+ GStrv short_names);
-struct xkb_keymap * meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap);
+struct xkb_keymap * meta_keymap_native_get_xkb_keymap_in_impl (MetaKeymapNative *keymap);
void meta_keymap_native_update_in_impl (MetaKeymapNative *keymap,
MetaSeatImpl *seat_impl,
diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c
index f55b8bd056..f11fd44866 100644
--- a/src/backends/native/meta-keymap-native.c
+++ b/src/backends/native/meta-keymap-native.c
@@ -203,13 +203,13 @@ update_keymap_in_main (gpointer user_data)
}
void
-meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
- MetaSeatImpl *seat_impl,
- MetaKeymapDescription *keymap_description,
- struct xkb_keymap *xkb_keymap,
- struct xkb_state *xkb_state,
- GStrv display_names,
- GStrv short_names)
+meta_keymap_native_set_keymap_in_impl (MetaKeymapNative *keymap,
+ MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ struct xkb_keymap *xkb_keymap,
+ struct xkb_state *xkb_state,
+ GStrv display_names,
+ GStrv short_names)
{
UpdateKeymapData *data;
@@ -231,7 +231,7 @@ meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap,
}
struct xkb_keymap *
-meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap)
+meta_keymap_native_get_xkb_keymap_in_impl (MetaKeymapNative *keymap)
{
return keymap->impl.keymap;
}
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index 2926bab779..ca7a9aed5a 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -3028,7 +3028,7 @@ meta_seat_impl_set_keyboard_numlock_in_impl (MetaSeatImpl *seat_impl,
MetaKeymapNative *keymap;
keymap = seat_impl->keymap;
- xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (keymap);
+ xkb_keymap = meta_keymap_native_get_xkb_keymap_in_impl (keymap);
numlock = (1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod2"));
@@ -3180,7 +3180,7 @@ update_keyboard_leds (MetaSeatImpl *seat_impl)
G_STATIC_ASSERT (G_N_ELEMENTS (led_map) == N_KEYBOARD_LEDS);
- xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap);
+ xkb_keymap = meta_keymap_native_get_xkb_keymap_in_impl (seat_impl->keymap);
if (!xkb_keymap)
return;
@@ -3223,7 +3223,7 @@ input_thread (MetaSeatImpl *seat_impl)
seat_impl->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL);
- xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap);
+ xkb_keymap = meta_keymap_native_get_xkb_keymap_in_impl (seat_impl->keymap);
if (xkb_keymap)
{
@@ -3715,7 +3715,7 @@ meta_seat_impl_update_xkb_state_in_impl (MetaSeatImpl *seat_impl)
g_rw_lock_writer_lock (&seat_impl->state_lock);
- xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap);
+ xkb_keymap = meta_keymap_native_get_xkb_keymap_in_impl (seat_impl->keymap);
meta_seat_impl_update_xkb_state_in_impl_unlocked (seat_impl,
xkb_keymap,
seat_impl->layout_idx);
@@ -3820,15 +3820,15 @@ meta_seat_impl_reclaim_devices (MetaSeatImpl *seat_impl)
}
gboolean
-meta_seat_impl_set_keyboard_map_finish (MetaSeatImpl *seat_impl,
- GAsyncResult *result,
- GError **error)
+meta_seat_impl_set_keymap_finish (MetaSeatImpl *seat_impl,
+ GAsyncResult *result,
+ GError **error)
{
GTask *task = G_TASK (result);
g_return_val_if_fail (g_task_is_valid (result, seat_impl), FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
- meta_seat_impl_set_keyboard_map_async, FALSE);
+ meta_seat_impl_set_keymap_async, FALSE);
return g_task_propagate_boolean (task, error);
}
@@ -3878,7 +3878,7 @@ update_layout_index_unlocked (MetaSeatImpl *seat_impl,
}
static gboolean
-set_keyboard_map (GTask *task)
+set_keymap (GTask *task)
{
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
MetaSeatImplPrivate *priv =
@@ -3936,13 +3936,13 @@ set_keyboard_map (GTask *task)
data->layout_index);
keymap = seat_impl->keymap;
- meta_keymap_native_set_keyboard_map_in_impl (keymap,
- seat_impl,
- keymap_description,
- xkb_keymap,
- seat_impl->xkb,
- g_steal_pointer (&display_names),
- g_steal_pointer (&short_names));
+ meta_keymap_native_set_keymap_in_impl (keymap,
+ seat_impl,
+ keymap_description,
+ xkb_keymap,
+ seat_impl->xkb,
+ g_steal_pointer (&display_names),
+ g_steal_pointer (&short_names));
xkb_keymap_unref (xkb_keymap);
}
else
@@ -3958,7 +3958,7 @@ set_keyboard_map (GTask *task)
}
/**
- * meta_seat_impl_set_keyboard_map_async: (skip)
+ * meta_seat_impl_set_keymap_async: (skip)
* @seat_impl: the #ClutterSeat created by the evdev backend
* @keymap: the new keymap
* @cancellable: a #GCancellable
@@ -3971,12 +3971,12 @@ set_keyboard_map (GTask *task)
* is pressed when calling this function.
*/
void
-meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
- MetaKeymapDescription *keymap_description,
- xkb_layout_index_t layout_index,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+meta_seat_impl_set_keymap_async (MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ xkb_layout_index_t layout_index,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GTask *task;
SetKeymapData *data;
@@ -3985,13 +3985,13 @@ meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
g_return_if_fail (keymap_description);
task = g_task_new (seat_impl, cancellable, callback, user_data);
- g_task_set_source_tag (task, meta_seat_impl_set_keyboard_map_async);
+ g_task_set_source_tag (task, meta_seat_impl_set_keymap_async);
data = g_new0 (SetKeymapData, 1);
data->keymap_description = meta_keymap_description_ref (keymap_description);
data->layout_index = layout_index;
g_task_set_task_data (task, data, set_keymap_data_free);
- meta_seat_impl_run_input_task (seat_impl, task, (GSourceFunc) set_keyboard_map);
+ meta_seat_impl_run_input_task (seat_impl, task, (GSourceFunc) set_keymap);
g_object_unref (task);
}
diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h
index c4692cac19..2a31db19b7 100644
--- a/src/backends/native/meta-seat-impl.h
+++ b/src/backends/native/meta-seat-impl.h
@@ -185,16 +185,16 @@ void meta_seat_impl_reclaim_devices (MetaSeatImpl *seat_impl);
struct xkb_state * meta_seat_impl_get_xkb_state_in_impl (MetaSeatImpl *seat_impl);
-gboolean meta_seat_impl_set_keyboard_map_finish (MetaSeatImpl *seat_impl,
- GAsyncResult *result,
- GError **error);
-
-void meta_seat_impl_set_keyboard_map_async (MetaSeatImpl *seat_impl,
- MetaKeymapDescription *keymap_description,
- xkb_layout_index_t layout_index,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+gboolean meta_seat_impl_set_keymap_finish (MetaSeatImpl *seat_impl,
+ GAsyncResult *result,
+ GError **error);
+
+void meta_seat_impl_set_keymap_async (MetaSeatImpl *seat_impl,
+ MetaKeymapDescription *keymap_description,
+ xkb_layout_index_t layout_index,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
void meta_seat_impl_set_keyboard_repeat_in_impl (MetaSeatImpl *seat_impl,
gboolean repeat,
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index 2722b1d970..dbb0a3534a 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -66,11 +66,11 @@ static guint signals[N_SIGNALS];
G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT)
-static gboolean meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
- MetaKeymapDescription *description,
- xkb_layout_index_t layout_index,
- GCancellable *cancellable,
- GError **error);
+static gboolean meta_seat_native_set_keymap_sync (MetaSeatNative *seat_native,
+ MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
+ GCancellable *cancellable,
+ GError **error);
static gboolean
meta_seat_native_handle_event_post (ClutterSeat *seat,
@@ -226,9 +226,9 @@ meta_seat_native_constructed (GObject *object)
NULL,
NULL,
NULL);
- if (!meta_seat_native_set_keyboard_map_sync (seat,
- keymap_description, 0,
- NULL, &error))
+ if (!meta_seat_native_set_keymap_sync (seat,
+ keymap_description, 0,
+ NULL, &error))
g_warning ("Failed to set keyboard map: %s", error->message);
if (G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed)
@@ -575,15 +575,15 @@ meta_seat_native_reclaim_devices (MetaSeatNative *seat)
}
gboolean
-meta_seat_native_set_keyboard_map_finish (MetaSeatNative *seat_native,
- GAsyncResult *result,
- GError **error)
+meta_seat_native_set_keymap_finish (MetaSeatNative *seat_native,
+ GAsyncResult *result,
+ GError **error)
{
GTask *task = G_TASK (result);
g_return_val_if_fail (g_task_is_valid (result, seat_native), FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
- meta_seat_native_set_keyboard_map_async, FALSE);
+ meta_seat_native_set_keymap_async, FALSE);
return g_task_propagate_boolean (task, error);
}
@@ -597,7 +597,7 @@ set_impl_keyboard_map_cb (GObject *source_object,
g_autoptr (GTask) task = G_TASK (user_data);
g_autoptr (GError) error = NULL;
- if (!meta_seat_impl_set_keyboard_map_finish (seat_impl, result, &error))
+ if (!meta_seat_impl_set_keymap_finish (seat_impl, result, &error))
{
g_task_return_error (task, g_steal_pointer (&error));
return;
@@ -607,7 +607,7 @@ set_impl_keyboard_map_cb (GObject *source_object,
}
/**
- * meta_seat_native_set_keyboard_map_async: (skip)
+ * meta_seat_native_set_keymap_async: (skip)
* @seat: the #ClutterSeat created by the evdev backend
* @keymap: the new keymap
*
@@ -617,24 +617,24 @@ set_impl_keyboard_map_cb (GObject *source_object,
* is pressed when calling this function.
*/
void
-meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
- MetaKeymapDescription *description,
- xkb_layout_index_t layout_index,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+meta_seat_native_set_keymap_async (MetaSeatNative *seat,
+ MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
g_autoptr (GTask) task = NULL;
task = g_task_new (G_OBJECT (seat), cancellable, callback, user_data);
- g_task_set_source_tag (task, meta_seat_native_set_keyboard_map_async);
+ g_task_set_source_tag (task, meta_seat_native_set_keymap_async);
- meta_seat_impl_set_keyboard_map_async (seat->impl,
- description,
- layout_index,
- cancellable,
- set_impl_keyboard_map_cb,
- g_object_ref (task));
+ meta_seat_impl_set_keymap_async (seat->impl,
+ description,
+ layout_index,
+ cancellable,
+ set_impl_keyboard_map_cb,
+ g_object_ref (task));
}
static void
@@ -647,7 +647,7 @@ sync_set_impl_keyboard_map_cb (GObject *source_object,
GTask *task = G_TASK (user_data);
GMainLoop *main_loop = g_task_get_task_data (task);
- if (!meta_seat_impl_set_keyboard_map_finish (seat_impl, result, &error))
+ if (!meta_seat_impl_set_keymap_finish (seat_impl, result, &error))
{
g_task_return_error (task, g_steal_pointer (&error));
g_main_loop_quit (main_loop);
@@ -659,11 +659,11 @@ sync_set_impl_keyboard_map_cb (GObject *source_object,
}
static gboolean
-meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
- MetaKeymapDescription *description,
- xkb_layout_index_t layout_index,
- GCancellable *cancellable,
- GError **error)
+meta_seat_native_set_keymap_sync (MetaSeatNative *seat_native,
+ MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
+ GCancellable *cancellable,
+ GError **error)
{
g_autoptr (GMainContext) main_context = NULL;
g_autoptr (GMainLoop) main_loop = NULL;
@@ -677,12 +677,12 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
task = g_task_new (NULL, NULL, NULL, NULL);
g_task_set_task_data (task, main_loop, NULL);
- meta_seat_impl_set_keyboard_map_async (seat_native->impl,
- description,
- layout_index,
- cancellable,
- sync_set_impl_keyboard_map_cb,
- task);
+ meta_seat_impl_set_keymap_async (seat_native->impl,
+ description,
+ layout_index,
+ cancellable,
+ sync_set_impl_keyboard_map_cb,
+ task);
g_main_loop_run (main_loop);
g_main_context_pop_thread_default (main_context);
@@ -708,7 +708,7 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
}
/**
- * meta_seat_native_get_keyboard_map: (skip)
+ * meta_seat_native_get_keymap: (skip)
* @seat: the #ClutterSeat created by the evdev backend
*
* Retrieves the #xkb_keymap in use by the evdev backend.
@@ -716,7 +716,7 @@ meta_seat_native_set_keyboard_map_sync (MetaSeatNative *seat_native,
* Return value: the #xkb_keymap.
*/
struct xkb_keymap *
-meta_seat_native_get_keyboard_map (MetaSeatNative *seat)
+meta_seat_native_get_xkb_keymap (MetaSeatNative *seat)
{
g_return_val_if_fail (META_IS_SEAT_NATIVE (seat), NULL);
@@ -724,7 +724,7 @@ meta_seat_native_get_keyboard_map (MetaSeatNative *seat)
}
MetaKeymapDescription *
-meta_seat_native_get_keyboard_map_description (MetaSeatNative *seat_native)
+meta_seat_native_get_keymap_description (MetaSeatNative *seat_native)
{
g_return_val_if_fail (seat_native->keymap_description, NULL);
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index 7fbe7dd3e7..ce3551d4ad 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -101,21 +101,21 @@ void meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callba
void meta_seat_native_release_devices (MetaSeatNative *seat);
void meta_seat_native_reclaim_devices (MetaSeatNative *seat);
-void meta_seat_native_set_keyboard_map_async (MetaSeatNative *seat,
- MetaKeymapDescription *description,
- xkb_layout_index_t layout_index,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void meta_seat_native_set_keymap_async (MetaSeatNative *seat,
+ MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
-gboolean meta_seat_native_set_keyboard_map_finish (MetaSeatNative *seat_native,
- GAsyncResult *result,
- GError **error);
+gboolean meta_seat_native_set_keymap_finish (MetaSeatNative *seat_native,
+ GAsyncResult *result,
+ GError **error);
META_EXPORT_TEST
-struct xkb_keymap * meta_seat_native_get_keyboard_map (MetaSeatNative *seat);
+struct xkb_keymap * meta_seat_native_get_xkb_keymap (MetaSeatNative *seat);
-MetaKeymapDescription * meta_seat_native_get_keyboard_map_description (MetaSeatNative *seat_native);
+MetaKeymapDescription * meta_seat_native_get_keymap_description (MetaSeatNative *seat_native);
xkb_layout_index_t meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat);
diff --git a/src/backends/native/meta-virtual-input-device-native.c b/src/backends/native/meta-virtual-input-device-native.c
index e33925d7ba..777b4241eb 100644
--- a/src/backends/native/meta-virtual-input-device-native.c
+++ b/src/backends/native/meta-virtual-input-device-native.c
@@ -483,7 +483,8 @@ pick_keycode_for_keyval_in_current_group_in_impl (ClutterVirtualInputDevice *vir
seat = clutter_virtual_input_device_get_seat (virtual_device);
keymap = clutter_seat_get_keymap (seat);
- xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (META_KEYMAP_NATIVE (keymap));
+ xkb_keymap =
+ meta_keymap_native_get_xkb_keymap_in_impl (META_KEYMAP_NATIVE (keymap));
state = meta_seat_impl_get_xkb_state_in_impl (seat_native->impl);
layout = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE);
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index a26b1a7bf4..b55dfc0a16 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -670,7 +670,7 @@ meta_test_native_keyboard_map_modifiers (void)
ClutterSeat *seat = meta_backend_get_default_seat (backend);
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
struct xkb_keymap *xkb_keymap =
- meta_seat_native_get_keyboard_map (seat_native);
+ meta_seat_native_get_xkb_keymap (seat_native);
xkb_mod_mask_t shift_mask =
1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT);
xkb_mod_mask_t alt_mask =
--
2.54.0
From 92e1763f133db6b5909a4989df2ad8c26f2c1fd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 28 Jan 2026 22:15:39 +0100
Subject: [PATCH 30/32] backend: Rename get_keymap() to get_xkb_keymap()
This makes it clearer it's not a ClutterKeymap that is returned.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4699>
(cherry picked from commit 149973014c5abf25c058a081ee6fdab605bed836)
---
src/backends/meta-backend-private.h | 4 ++--
src/backends/meta-backend.c | 4 ++--
src/backends/meta-eis-client.c | 2 +-
src/backends/meta-input-capture-session.c | 2 +-
src/backends/native/meta-backend-native.c | 4 ++--
src/core/keybindings.c | 4 ++--
src/tests/keyboard-map-tests.c | 20 ++++++++++----------
src/wayland/meta-wayland-keyboard.c | 6 ++++--
8 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 8b61738922..45c02f2204 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -130,7 +130,7 @@ struct _MetaBackendClass
xkb_layout_index_t layout_index,
GTask *task);
- struct xkb_keymap * (* get_keymap) (MetaBackend *backend);
+ struct xkb_keymap * (* get_xkb_keymap) (MetaBackend *backend);
MetaKeymapDescription * (* get_keymap_description) (MetaBackend *backend);
@@ -209,7 +209,7 @@ void meta_backend_finish_touch_sequence (MetaBackend *backend,
MetaSequenceState state);
META_EXPORT_TEST
-struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
+struct xkb_keymap * meta_backend_get_xkb_keymap (MetaBackend *backend);
META_EXPORT_TEST
xkb_layout_index_t meta_backend_get_keymap_layout_group (MetaBackend *backend);
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 143797213d..7c2a520a0d 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -1810,9 +1810,9 @@ meta_backend_set_keymap_async (MetaBackend *backend,
}
struct xkb_keymap *
-meta_backend_get_keymap (MetaBackend *backend)
+meta_backend_get_xkb_keymap (MetaBackend *backend)
{
- return META_BACKEND_GET_CLASS (backend)->get_keymap (backend);
+ return META_BACKEND_GET_CLASS (backend)->get_xkb_keymap (backend);
}
/**
diff --git a/src/backends/meta-eis-client.c b/src/backends/meta-eis-client.c
index 167e5ca030..d017c3b09e 100644
--- a/src/backends/meta-eis-client.c
+++ b/src/backends/meta-eis-client.c
@@ -242,7 +242,7 @@ configure_keyboard (MetaEisClient *client,
eis_device_configure_capability (eis_device, EIS_DEVICE_CAP_KEYBOARD);
xkb_keymap =
- meta_backend_get_keymap (meta_eis_get_backend (client->eis));
+ meta_backend_get_xkb_keymap (meta_eis_get_backend (client->eis));
if (!xkb_keymap)
return;
diff --git a/src/backends/meta-input-capture-session.c b/src/backends/meta-input-capture-session.c
index 67d50c8e8c..15acbe3222 100644
--- a/src/backends/meta-input-capture-session.c
+++ b/src/backends/meta-input-capture-session.c
@@ -244,7 +244,7 @@ ensure_xkb_keymap_file (MetaInputCaptureSession *session,
if (session->keymap_file)
return session->keymap_file;
- keymap = meta_backend_get_keymap (backend);
+ keymap = meta_backend_get_xkb_keymap (backend);
if (!keymap)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 66105d6cb4..15e05a50be 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -355,7 +355,7 @@ meta_backend_native_set_keymap_async (MetaBackend *backend,
}
static struct xkb_keymap *
-meta_backend_native_get_keymap (MetaBackend *backend)
+meta_backend_native_get_xkb_keymap (MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
@@ -903,7 +903,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
backend_class->get_current_logical_monitor = meta_backend_native_get_current_logical_monitor;
backend_class->set_keymap_async = meta_backend_native_set_keymap_async;
- backend_class->get_keymap = meta_backend_native_get_keymap;
+ backend_class->get_xkb_keymap = meta_backend_native_get_xkb_keymap;
backend_class->get_keymap_description = meta_backend_native_get_keymap_description;
backend_class->get_keymap_layout_group = meta_backend_native_get_keymap_layout_group;
backend_class->update_stage = meta_backend_native_update_stage;
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 6f879eed8e..486da03689 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -239,7 +239,7 @@ key_combo_key (MetaResolvedKeyCombo *resolved_combo,
static void
reload_modmap (MetaKeyBindingManager *keys)
{
- struct xkb_keymap *keymap = meta_backend_get_keymap (keys->backend);
+ struct xkb_keymap *keymap = meta_backend_get_xkb_keymap (keys->backend);
struct xkb_state *scratch_state;
xkb_mod_mask_t scroll_lock_mask;
xkb_mod_mask_t dummy_mask;
@@ -800,7 +800,7 @@ reload_active_keyboard_layouts (MetaKeyBindingManager *keys)
clear_active_keyboard_layouts (keys);
- keymap = meta_backend_get_keymap (keys->backend);
+ keymap = meta_backend_get_xkb_keymap (keys->backend);
layout_index = meta_backend_get_keymap_layout_group (keys->backend);
primary_layout = (MetaKeyBindingKeyboardLayout) {
.keymap = xkb_keymap_ref (keymap),
diff --git a/src/tests/keyboard-map-tests.c b/src/tests/keyboard-map-tests.c
index b55dfc0a16..c31b176c7c 100644
--- a/src/tests/keyboard-map-tests.c
+++ b/src/tests/keyboard-map-tests.c
@@ -165,7 +165,7 @@ meta_test_native_keyboard_map_set_async (void)
ClutterSeat *seat = meta_backend_get_default_seat (backend);
ClutterKeymap *keymap = clutter_seat_get_keymap (seat);
g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL;
- struct xkb_keymap *xkb_keymap = meta_backend_get_keymap (backend);
+ struct xkb_keymap *xkb_keymap = meta_backend_get_xkb_keymap (backend);
xkb_mod_mask_t alt_mask =
1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT);
ModMaskTuple expected_mods = { alt_mask, 0, 0 };
@@ -234,12 +234,12 @@ meta_test_native_keyboard_map_set_async (void)
meta_backend_set_keymap_async (backend, keymap_description, 0,
NULL, set_keymap_cb, &done);
- g_assert_true (xkb_keymap == meta_backend_get_keymap (backend));
+ g_assert_true (xkb_keymap == meta_backend_get_xkb_keymap (backend));
while (!done || expected_next_handler)
g_main_context_iteration (NULL, TRUE);
- new_xkb_keymap = meta_backend_get_keymap (backend);
+ new_xkb_keymap = meta_backend_get_xkb_keymap (backend);
g_assert_true (new_xkb_keymap != xkb_keymap);
g_assert_cmpuint (xkb_keymap_num_layouts (new_xkb_keymap), ==, 1);
g_assert_cmpstr (xkb_keymap_layout_get_name (new_xkb_keymap, 0),
@@ -266,7 +266,7 @@ meta_test_native_keyboard_map_change_layout (void)
MetaBackend *backend = meta_context_get_backend (test_context);
ClutterSeat *seat = meta_backend_get_default_seat (backend);
g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL;
- struct xkb_keymap *xkb_keymap = meta_backend_get_keymap (backend);
+ struct xkb_keymap *xkb_keymap = meta_backend_get_xkb_keymap (backend);
g_autoptr (MetaKeymapDescription) keymap_description = NULL;
struct xkb_keymap *new_xkb_keymap;
gboolean done = FALSE;
@@ -289,7 +289,7 @@ meta_test_native_keyboard_map_change_layout (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- new_xkb_keymap = meta_backend_get_keymap (backend);
+ new_xkb_keymap = meta_backend_get_xkb_keymap (backend);
g_assert_true (new_xkb_keymap != xkb_keymap);
g_assert_cmpuint (xkb_keymap_num_layouts (new_xkb_keymap), ==, 2);
g_assert_cmpstr (xkb_keymap_layout_get_name (new_xkb_keymap, 0),
@@ -389,7 +389,7 @@ meta_test_native_keyboard_map_set_layout_index (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- keymap = meta_backend_get_keymap (backend);
+ keymap = meta_backend_get_xkb_keymap (backend);
g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
==,
@@ -443,7 +443,7 @@ meta_test_native_keyboard_map_lock_layout (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- keymap = xkb_keymap_ref (meta_backend_get_keymap (backend));
+ keymap = xkb_keymap_ref (meta_backend_get_xkb_keymap (backend));
g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
==,
@@ -477,7 +477,7 @@ meta_test_native_keyboard_map_lock_layout (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- g_assert_true (keymap == meta_backend_get_keymap (backend));
+ g_assert_true (keymap == meta_backend_get_xkb_keymap (backend));
/*
* Set the same keymap with a different layout index. Should take effect.
@@ -521,7 +521,7 @@ meta_test_native_keyboard_map_lock_layout (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- keymap = meta_backend_get_keymap (backend);
+ keymap = meta_backend_get_xkb_keymap (backend);
g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 1);
g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
==,
@@ -538,7 +538,7 @@ meta_test_native_keyboard_map_lock_layout (void)
while (!done)
g_main_context_iteration (NULL, TRUE);
- keymap = meta_backend_get_keymap (backend);
+ keymap = meta_backend_get_xkb_keymap (backend);
g_assert_cmpuint (xkb_keymap_num_layouts (keymap), ==, 2);
g_assert_cmpstr (xkb_keymap_layout_get_name (keymap, 0),
==,
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index 451c9d834d..a6329785fd 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -209,7 +209,8 @@ on_keymap_changed (MetaBackend *backend,
{
MetaWaylandKeyboard *keyboard = data;
- meta_wayland_keyboard_take_keymap (keyboard, meta_backend_get_keymap (backend));
+ meta_wayland_keyboard_take_keymap (keyboard,
+ meta_backend_get_xkb_keymap (backend));
}
static void
@@ -454,7 +455,8 @@ meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard)
g_signal_connect (backend, "keymap-layout-group-changed",
G_CALLBACK (on_keymap_layout_group_changed), keyboard);
- meta_wayland_keyboard_take_keymap (keyboard, meta_backend_get_keymap (backend));
+ meta_wayland_keyboard_take_keymap (keyboard,
+ meta_backend_get_xkb_keymap (backend));
meta_wayland_keyboard_set_focus (keyboard, seat->input_focus);
}
--
2.54.0
From 5f7591a2fd4e362ed50484dceaefec8cddffec56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 19 May 2026 23:50:29 +0200
Subject: [PATCH 31/32] Let X11 backend gracefully handle rules keymap
descriptions
This means ones set from remote desktop servers wont work, but this is
not supported anyway, so lets not bother.
---
.../meta-keymap-description-private.h | 6 ++
src/backends/meta-keymap-description.c | 24 ++++++++
src/backends/x11/cm/meta-backend-x11-cm.c | 61 +++++++++----------
src/backends/x11/meta-backend-x11.c | 6 +-
src/backends/x11/meta-keymap-x11.c | 3 +-
.../x11/nested/meta-backend-x11-nested.c | 20 ++----
6 files changed, 69 insertions(+), 51 deletions(-)
diff --git a/src/backends/meta-keymap-description-private.h b/src/backends/meta-keymap-description-private.h
index f53092cd27..616bc94b2c 100644
--- a/src/backends/meta-keymap-description-private.h
+++ b/src/backends/meta-keymap-description-private.h
@@ -63,3 +63,9 @@ void meta_keymap_description_reset_owner (MetaKeymapDescription *keymap_des
MetaKeymapDescriptionOwner * meta_keymap_description_get_owner (MetaKeymapDescription *keymap_description);
MetaKeymapDescriptionOwner * meta_keymap_description_resets_owner (MetaKeymapDescription *keymap_description);
+
+gboolean meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
+ const char **model,
+ const char **layout,
+ const char **variant,
+ const char **options);
diff --git a/src/backends/meta-keymap-description.c b/src/backends/meta-keymap-description.c
index 4d077626df..29b1ad2c16 100644
--- a/src/backends/meta-keymap-description.c
+++ b/src/backends/meta-keymap-description.c
@@ -386,3 +386,27 @@ meta_keymap_description_resets_owner (MetaKeymapDescription *keymap_description)
{
return keymap_description->resets_owner;
}
+
+gboolean
+meta_keymap_description_get_rules (MetaKeymapDescription *keymap_description,
+ const char **model,
+ const char **layout,
+ const char **variant,
+ const char **options)
+{
+ switch (keymap_description->source)
+ {
+ case META_KEYMAP_DESCRIPTION_SOURCE_RULES:
+ {
+ *model = keymap_description->rules.model;
+ *layout = keymap_description->rules.layout;
+ *variant = keymap_description->rules.variant;
+ *options = keymap_description->rules.options;
+ return TRUE;
+ }
+ case META_KEYMAP_DESCRIPTION_SOURCE_FD:
+ return FALSE;
+ }
+
+ g_assert_not_reached ();
+}
diff --git a/src/backends/x11/cm/meta-backend-x11-cm.c b/src/backends/x11/cm/meta-backend-x11-cm.c
index bc8ad6dfe2..18daf62ac1 100644
--- a/src/backends/x11/cm/meta-backend-x11-cm.c
+++ b/src/backends/x11/cm/meta-backend-x11-cm.c
@@ -386,42 +386,42 @@ apply_keymap (MetaBackendX11 *x11)
}
static void
-meta_backend_x11_cm_set_keymap_async (MetaBackend *backend,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GTask *task)
+meta_backend_x11_cm_set_keymap_async (MetaBackend *backend,
+ MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
+ GTask *task)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (x11);
+ Display *xdisplay = meta_backend_x11_get_xdisplay (x11);
+ const char *models;
+ const char *layouts;
+ const char *variants;
+ const char *options;
+ gboolean changed = FALSE;
+
+ if (!meta_keymap_description_get_rules (description,
+ &models,
+ &layouts,
+ &variants,
+ &options))
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "X11 backend cant set layout from file descriptor");
+ g_object_unref (task);
+ return;
+ }
- g_free (x11_cm->keymap_layouts);
- x11_cm->keymap_layouts = g_strdup (layouts);
- g_free (x11_cm->keymap_variants);
- x11_cm->keymap_variants = g_strdup (variants);
- g_free (x11_cm->keymap_options);
- x11_cm->keymap_options = g_strdup (options);
- g_free (x11_cm->keymap_model);
- x11_cm->keymap_model = g_strdup (model);
-
- apply_keymap (x11);
+ changed |= g_set_str (&x11_cm->keymap_layouts, layouts);
+ changed |= g_set_str (&x11_cm->keymap_variants, variants);
+ changed |= g_set_str (&x11_cm->keymap_options, options);
+ changed |= g_set_str (&x11_cm->keymap_model, models);
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
-static void
-meta_backend_x11_cm_set_keymap_layout_group_async (MetaBackend *backend,
- xkb_layout_index_t idx,
- GTask *task)
-{
- MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
- MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (x11);
- Display *xdisplay = meta_backend_x11_get_xdisplay (x11);
+ if (changed)
+ apply_keymap (x11);
- x11_cm->locked_group = idx;
- XkbLockGroup (xdisplay, XkbUseCoreKbd, idx);
+ x11_cm->locked_group = layout_index;
+ XkbLockGroup (xdisplay, XkbUseCoreKbd, layout_index);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
@@ -567,7 +567,6 @@ meta_backend_x11_cm_class_init (MetaBackendX11CmClass *klass)
backend_class->update_stage = meta_backend_x11_cm_update_stage;
backend_class->select_stage_events = meta_backend_x11_cm_select_stage_events;
backend_class->set_keymap_async = meta_backend_x11_cm_set_keymap_async;
- backend_class->set_keymap_layout_group_async = meta_backend_x11_cm_set_keymap_layout_group_async;
backend_x11_class->handle_host_xevent = meta_backend_x11_cm_handle_host_xevent;
backend_x11_class->translate_device_event = meta_backend_x11_cm_translate_device_event;
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
index 9e119f2c93..59fa358d30 100644
--- a/src/backends/x11/meta-backend-x11.c
+++ b/src/backends/x11/meta-backend-x11.c
@@ -876,7 +876,7 @@ meta_backend_x11_get_current_logical_monitor (MetaBackend *backend)
}
static struct xkb_keymap *
-meta_backend_x11_get_keymap (MetaBackend *backend)
+meta_backend_x11_get_xkb_keymap (MetaBackend *backend)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
@@ -931,7 +931,7 @@ init_xkb_state (MetaBackendX11 *x11)
int32_t device_id;
struct xkb_state *state;
- keymap = meta_backend_get_keymap (META_BACKEND (x11));
+ keymap = meta_backend_get_xkb_keymap (META_BACKEND (x11));
device_id = xkb_x11_get_core_keyboard_device_id (priv->xcb);
state = xkb_x11_state_new_from_device (keymap, priv->xcb, device_id);
@@ -1096,7 +1096,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
backend_class->ungrab_keyboard = meta_backend_x11_ungrab_keyboard;
backend_class->finish_touch_sequence = meta_backend_x11_finish_touch_sequence;
backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
- backend_class->get_keymap = meta_backend_x11_get_keymap;
+ backend_class->get_xkb_keymap = meta_backend_x11_get_xkb_keymap;
backend_class->get_keymap_layout_group = meta_backend_x11_get_keymap_layout_group;
}
diff --git a/src/backends/x11/meta-keymap-x11.c b/src/backends/x11/meta-keymap-x11.c
index 01107af07c..cdcb69ac45 100644
--- a/src/backends/x11/meta-keymap-x11.c
+++ b/src/backends/x11/meta-keymap-x11.c
@@ -227,7 +227,8 @@ update_modifiers (MetaKeymapX11 *keymap_x11,
keymap_x11->current_group,
xkb_event->state.base_mods,
xkb_event->state.latched_mods,
- xkb_event->state.locked_mods);
+ xkb_event->state.locked_mods,
+ TRUE);
if (num_lock_state != old_num_lock_state)
{
diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c b/src/backends/x11/nested/meta-backend-x11-nested.c
index 24377a90be..5cf7fe8667 100644
--- a/src/backends/x11/nested/meta-backend-x11-nested.c
+++ b/src/backends/x11/nested/meta-backend-x11-nested.c
@@ -149,21 +149,10 @@ meta_backend_x11_nested_select_stage_events (MetaBackend *backend)
}
static void
-meta_backend_x11_nested_set_keymap_async (MetaBackend *backend,
- const char *layouts,
- const char *variants,
- const char *options,
- const char *model,
- GTask *task)
-{
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
-static void
-meta_backend_x11_nested_set_keymap_layout_group_async (MetaBackend *backend,
- xkb_layout_index_t idx,
- GTask *task)
+meta_backend_x11_nested_set_keymap_async (MetaBackend *backend,
+ MetaKeymapDescription *description,
+ xkb_layout_index_t layout_index,
+ GTask *task)
{
g_task_return_boolean (task, TRUE);
g_object_unref (task);
@@ -292,7 +281,6 @@ meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass)
backend_class->update_stage = meta_backend_x11_nested_update_stage;
backend_class->select_stage_events = meta_backend_x11_nested_select_stage_events;
backend_class->set_keymap_async = meta_backend_x11_nested_set_keymap_async;
- backend_class->set_keymap_layout_group_async = meta_backend_x11_nested_set_keymap_layout_group_async;
backend_class->is_lid_closed = meta_backend_x11_nested_is_lid_closed;
backend_class->set_pointer_constraint = meta_backend_x11_nested_set_pointer_constraint;
--
2.54.0
From 2eea8d03d233a5c20078baaf5fba1aec566ce614 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 20 May 2026 00:05:45 +0200
Subject: [PATCH 32/32] mdk/session: Don't depend on newer GTK
A symbol needed for keymap changes doesn't exist in RHEL10, so lets
build without it, and fall back to using layout index 0.
---
mdk/mdk-session.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/mdk/mdk-session.c b/mdk/mdk-session.c
index 239d5dacd9..bf253b1b91 100644
--- a/mdk/mdk-session.c
+++ b/mdk/mdk-session.c
@@ -140,7 +140,12 @@ maybe_sync_keymap (MdkSession *session)
}
xkb_keymap = gdk_wayland_device_get_xkb_keymap (keyboard);
+#if GTK_CHECK_VERSION (4,18,0)
layout_index = gdk_device_get_active_layout_index (keyboard);
+#else
+ g_warning_once ("Only able to set the first layout");
+ layout_index = 0;
+#endif
if (xkb_keymap == session->xkb_keymap &&
layout_index == session->layout_index)
@@ -208,7 +213,11 @@ maybe_sync_keymap (MdkSession *session)
return;
}
+#if GTK_CHECK_VERSION (4,18,0)
layout_index = gdk_device_get_active_layout_index (keyboard);
+#else
+ layout_index = 0;
+#endif
g_variant_builder_init (&options_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&options_builder, "{sv}",
--
2.54.0