Fix keyboard layouts getting out of sync in anaconda

This commit is contained in:
Ray Strode 2021-04-21 14:14:23 -04:00
parent c93b840f9c
commit fc46cee8bd
6 changed files with 515 additions and 373 deletions

View File

@ -0,0 +1,116 @@
From ab8482bab7981321f0f2fbd401907ac34028bb1a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 20 Apr 2021 09:27:01 -0400
Subject: [PATCH 1/4] gobject-utils: Log when executing deferred tasks
At the moment, the code defers execution until "later" in
various parts of the code to ensure a flood of related events
doesn't lead to a flood of duplicated work.
But, its on the called code to log at the moment.
This commit adds logging to the generic part of the code to
for clarity.
---
compositor/kiosk-gobject-utils.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/compositor/kiosk-gobject-utils.c b/compositor/kiosk-gobject-utils.c
index a0dfcd8..c38db7e 100644
--- a/compositor/kiosk-gobject-utils.c
+++ b/compositor/kiosk-gobject-utils.c
@@ -1,83 +1,87 @@
#include "config.h"
#include "kiosk-gobject-utils.h"
#define COALESCE_INTERVAL 250 /* milliseconds */
static void
on_task_wait_complete (GObject *self,
GTask *task)
{
KioskObjectCallback callback;
gpointer user_data;
gboolean completed;
g_autofree char *data_key = NULL;
+ g_debug ("KioskGObjectUtils: Executing deferred task '%s'", g_task_get_name (task));
+
callback = g_object_get_data (G_OBJECT (task), "callback");
user_data = g_object_get_data (G_OBJECT (task), "user-data");
completed = g_task_propagate_boolean (task, NULL);
if (completed) {
callback (self, user_data);
}
data_key = g_strdup_printf ("kiosk-gobject-utils-%p-%p-task",
callback, user_data);
g_object_set_data (G_OBJECT (self), data_key, NULL);
}
static gboolean
on_coalesce_timeout (GTask *task)
{
if (!g_task_return_error_if_cancelled (task)) {
g_task_return_boolean (task, TRUE);
}
return G_SOURCE_REMOVE;
}
void
kiosk_gobject_utils_queue_defer_callback (GObject *self,
const char *name,
GCancellable *cancellable,
KioskObjectCallback callback,
gpointer user_data)
{
g_autofree char *data_key = NULL;
g_autoptr (GSource) timeout_source = NULL;
GTask *task;
g_return_if_fail (G_IS_OBJECT (self));
g_return_if_fail (callback != NULL);
data_key = g_strdup_printf ("kiosk-gobject-utils-%p-%p-task",
callback, user_data);
task = g_object_get_data (G_OBJECT (self), data_key);
if (task != NULL) {
return;
}
timeout_source = g_timeout_source_new (COALESCE_INTERVAL);
- if (name != NULL) {
- g_source_set_name (timeout_source, name);
- }
-
task = g_task_new (self,
cancellable,
(GAsyncReadyCallback) on_task_wait_complete,
NULL);
+
+ if (name != NULL) {
+ g_task_set_name (task, name);
+ g_debug ("KioskGObjectUtils: Deferring task '%s' for %dms", name, COALESCE_INTERVAL);
+ }
+
g_task_attach_source (task, timeout_source, G_SOURCE_FUNC (on_coalesce_timeout));
g_object_set_data (G_OBJECT (task), "callback", callback);
g_object_set_data (G_OBJECT (task), "user-data", user_data);
g_object_set_data_full (G_OBJECT (self),
data_key,
task,
(GDestroyNotify)
g_object_unref);
}
--
2.30.2

View File

@ -1,4 +1,4 @@
From 83e38979f48829d4498b2df6ea62aafa34c1975b Mon Sep 17 00:00:00 2001
From f553708a756682d625f51e7c0f3d2a31f39442bb Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Apr 2021 14:39:55 -0400
Subject: [PATCH 2/4] input-sources-manager: Fix overzealous rename mistake
@ -184,5 +184,5 @@ index 58d7a4c..a1a4cfa 100644
old_input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);
--
2.31.1
2.30.2

View File

@ -1,7 +1,7 @@
From db59d653751018f9b79c2a38a996fc7f0692d6b5 Mon Sep 17 00:00:00 2001
From a944f0d27a42028ec18edb17f65957780c400104 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Apr 2021 13:28:00 -0400
Subject: [PATCH 1/4] compositor: Add signal for reporting X server events
Subject: [PATCH 3/4] compositor: Add signal for reporting X server events
The keyboard layout handling code currently doesn't notice
when the keyboard layout is changed using libxklavier, out from
@ -225,5 +225,5 @@ index dad7776..14f5de3 100644
return KIOSK_SERVICE (self->service);
--
2.31.1
2.30.2

View File

@ -1,219 +0,0 @@
From 60e52b132e9957452004c85a0999b37a2e46ff55 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Apr 2021 14:41:41 -0400
Subject: [PATCH 3/4] input-sources-manager: Add function to load input sources
from strings
kiosk_input_sources_manager_set_input_sources_from_system_settings
currently has code to load fetch the strings from localed and then
use them.
This commit moves the "use them" part to its own function so it can
be reused in a subsequent commit for something else.
---
compositor/kiosk-input-sources-manager.c | 73 ++++++++++++++++--------
1 file changed, 48 insertions(+), 25 deletions(-)
diff --git a/compositor/kiosk-input-sources-manager.c b/compositor/kiosk-input-sources-manager.c
index a1a4cfa..4b4ef62 100644
--- a/compositor/kiosk-input-sources-manager.c
+++ b/compositor/kiosk-input-sources-manager.c
@@ -793,147 +793,170 @@ kiosk_input_sources_manager_add_layout (KioskInputSourcesManager *self,
input_source_group = kiosk_input_sources_manager_add_new_input_source_group (self, options);
}
mapping_full = !kiosk_input_source_group_add_layout (input_source_group, xkb_layout, xkb_variant);
if (mapping_full) {
g_debug ("KioskInputSourcesManager: Keyboard mapping full, starting another one");
input_source_group = kiosk_input_sources_manager_add_new_input_source_group (self, options);
kiosk_input_source_group_add_layout (input_source_group, xkb_layout, xkb_variant);
}
}
void
kiosk_input_sources_manager_add_input_engine (KioskInputSourcesManager *self,
const char *engine_name,
const char *options)
{
KioskInputSourceGroup *input_source_group = NULL;
g_debug ("KioskInputSourcesManager: Adding input engine '%s'", engine_name);
input_source_group = kiosk_input_sources_manager_add_new_input_source_group (self, options);
kiosk_input_source_group_set_input_engine (input_source_group, engine_name);
kiosk_input_source_group_set_options (input_source_group, options);
}
-gboolean
-kiosk_input_sources_manager_set_input_sources_from_system_configuration (KioskInputSourcesManager *self)
+static gboolean
+kiosk_input_sources_manager_set_input_sources_from_strings (KioskInputSourcesManager *self,
+ const char *layouts_string,
+ const char *variants_string,
+ const char *options_string)
{
KioskInputSourceGroup *old_input_source_group;
g_autofree char *old_input_engine = NULL;
g_autofree char *old_selected_layout = NULL;
- const char *layouts_string = NULL;
g_auto (GStrv) layouts = NULL;
size_t number_of_layouts = 0;
- const char *variants_string = NULL;
g_auto (GStrv) variants = NULL;
size_t number_of_variants = 0;
- const char *options = NULL;
size_t i, j;
- gboolean input_source_group_active;
+ gboolean input_sources_active;
g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE);
- if (self->locale_proxy == NULL) {
- return FALSE;
- }
-
- g_debug ("KioskInputSourcesManager: Setting keymap from system configuration");
-
- layouts_string = sd_locale1_get_x11_layout (self->locale_proxy);
- g_debug ("KioskInputSourcesManager: System layout is '%s'", layouts_string);
-
layouts = g_strsplit (layouts_string, ",", -1);
number_of_layouts = g_strv_length (layouts);
- options = sd_locale1_get_x11_options (self->locale_proxy);
- g_debug ("KioskInputSourcesManager: System layout options are '%s'", options);
-
- variants_string = sd_locale1_get_x11_variant (self->locale_proxy);
- g_debug ("KioskInputSourcesManager: System layout variant is '%s'", variants_string);
variants = g_strsplit (variants_string, ",", -1);
number_of_variants = g_strv_length (variants);
if (number_of_layouts < number_of_variants) {
g_debug ("KioskInputSourcesManager: There is a layout variant mismatch");
return FALSE;
}
old_input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);
if (old_input_source_group != NULL) {
old_input_engine = g_strdup (kiosk_input_source_group_get_input_engine (old_input_source_group));
old_selected_layout = kiosk_input_source_group_get_selected_layout (old_input_source_group);
}
kiosk_input_sources_manager_clear_input_sources (self);
for (i = 0, j = 0; layouts[i] != NULL; i++) {
char *id = NULL;
const char *layout = layouts[i];
const char *variant = "";
if (variants[j] != NULL) {
variant = variants[j++];
}
if (variant[0] == '\0') {
id = g_strdup (layout);
} else {
id = g_strdup_printf ("%s+%s", layout, variant);
}
- kiosk_input_sources_manager_add_layout (self, id, options);
+ kiosk_input_sources_manager_add_layout (self, id, options_string);
}
- input_source_group_active = activate_best_available_input_source_group (self, old_input_engine, old_selected_layout);
+ input_sources_active = activate_best_available_input_source_group (self, old_input_engine, old_selected_layout);
- if (!input_source_group_active) {
+ if (!input_sources_active) {
+ return FALSE;
+ }
+
+ sync_dbus_service (self);
+
+ return TRUE;
+}
+
+gboolean
+kiosk_input_sources_manager_set_input_sources_from_system_configuration (KioskInputSourcesManager *self)
+{
+ const char *layouts_string = NULL;
+ const char *variants_string = NULL;
+ const char *options = NULL;
+
+ gboolean input_sources_active;
+
+ g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE);
+
+ if (self->locale_proxy == NULL) {
+ return FALSE;
+ }
+
+ g_debug ("KioskInputSourcesManager: Setting keymap from system configuration");
+
+ layouts_string = sd_locale1_get_x11_layout (self->locale_proxy);
+ g_debug ("KioskInputSourcesManager: System layout is '%s'", layouts_string);
+
+ options = sd_locale1_get_x11_options (self->locale_proxy);
+ g_debug ("KioskInputSourcesManager: System layout options are '%s'", options);
+
+ variants_string = sd_locale1_get_x11_variant (self->locale_proxy);
+ g_debug ("KioskInputSourcesManager: System layout variant is '%s'", variants_string);
+
+ input_sources_active = kiosk_input_sources_manager_set_input_sources_from_strings (self, layouts_string, variants_string, options);
+
+ if (!input_sources_active) {
const char * const *locales;
locales = sd_locale1_get_locale (self->locale_proxy);
- input_source_group_active = kiosk_input_sources_manager_set_input_sources_from_locales (self, locales, options);
+ input_sources_active = kiosk_input_sources_manager_set_input_sources_from_locales (self, locales, options);
}
sync_dbus_service (self);
self->overriding_configuration = FALSE;
- if (!input_source_group_active) {
+ if (!input_sources_active) {
g_debug ("KioskInputSourcesManager: System has no valid configured input sources");
return FALSE;
}
return TRUE;
}
static void
on_session_input_configuration_changed (KioskInputSourcesManager *self)
{
g_debug ("KioskInputSourcesManager: Session input sources configuration changed");
if (self->overriding_configuration) {
g_debug ("KioskInputSourcesManager: Ignoring change, because keymap is overriden");
return;
}
kiosk_input_sources_manager_set_input_sources_from_session_configuration (self);
}
static void
on_session_input_sources_setting_changed (KioskInputSourcesManager *self)
{
kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
"[kiosk-input-sources-manager] on_session_input_configuration_changed",
self->cancellable,
KIOSK_OBJECT_CALLBACK (on_session_input_configuration_changed),
NULL);
}
--
2.31.1

View File

@ -1,29 +1,100 @@
From c99306e0efcf3113d592bc963b4dfac6504b724d Mon Sep 17 00:00:00 2001
From 5b23d5f86f554373d4207d4f95c50bc86892e634 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Apr 2021 14:43:17 -0400
Subject: [PATCH 4/4] wip! Better support libxklavier
Subject: [PATCH 4/4] input-sources-manager: Support libxklavier managed
keyboard layouts
Mutter currently doesn't allow libxklavier to change the group out from
Mutter currently doesn't allow libxklavier to change the layout out from
under it.
This commit fixes that, but also makes sure that current layout state
stays in sync with X server state.
This commit fixes that on X being careful to make sure the current layout
state, as gnome-kiosk sees it, stays in sync with X server state.
---
compositor/kiosk-input-source-group.c | 17 +
compositor/kiosk-input-source-group.c | 47 +-
compositor/kiosk-input-source-group.h | 5 +-
compositor/kiosk-input-sources-manager.c | 142 ++++++
compositor/kiosk-x-keyboard-manager.c | 579 +++++++++++++++++++++++
compositor/kiosk-x-keyboard-manager.h | 22 +
compositor/kiosk-input-sources-manager.c | 143 ++++++
compositor/kiosk-input-sources-manager.h | 2 +
compositor/kiosk-x-keyboard-manager.c | 565 +++++++++++++++++++++++
compositor/kiosk-x-keyboard-manager.h | 29 ++
meson.build | 1 +
6 files changed, 765 insertions(+), 1 deletion(-)
7 files changed, 786 insertions(+), 6 deletions(-)
create mode 100644 compositor/kiosk-x-keyboard-manager.c
create mode 100644 compositor/kiosk-x-keyboard-manager.h
diff --git a/compositor/kiosk-input-source-group.c b/compositor/kiosk-input-source-group.c
index a0c924e..6e2712f 100644
index a0c924e..c33ca05 100644
--- a/compositor/kiosk-input-source-group.c
+++ b/compositor/kiosk-input-source-group.c
@@ -213,60 +213,66 @@ kiosk_input_source_group_set_input_engine (KioskInputSourceGroup *self,
@@ -1,67 +1,67 @@
#include "config.h"
#include "kiosk-input-source-group.h"
#include <stdlib.h>
#include <string.h>
#include <xkbcommon/xkbcommon.h>
#include <meta/meta-backend.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-languages.h>
#include <libgnome-desktop/gnome-xkb-info.h>
#include "kiosk-gobject-utils.h"
#include "kiosk-input-sources-manager.h"
#define KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS 3
struct _KioskInputSourceGroup
{
GObject parent;
/* weak references */
KioskInputSourcesManager *input_sources_manager;
KioskInputEngineManager *input_engine_manager;
+ KioskXKeyboardManager *x_keyboard_manager;
/* strong references */
char *input_engine_name;
GPtrArray *layouts;
GPtrArray *variants;
char *options;
/* state */
xkb_layout_index_t layout_index;
};
-
enum
{
PROP_INPUT_SOURCES_MANAGER = 1,
NUMBER_OF_PROPERTIES
};
static GParamSpec *kiosk_input_source_group_properties[NUMBER_OF_PROPERTIES] = { NULL, };
G_DEFINE_TYPE (KioskInputSourceGroup, kiosk_input_source_group, G_TYPE_OBJECT)
static void kiosk_input_source_group_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *param_spec);
static void kiosk_input_source_group_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *param_spec);
static void kiosk_input_source_group_constructed (GObject *object);
static void kiosk_input_source_group_dispose (GObject *object);
KioskInputSourceGroup *
kiosk_input_source_group_new (KioskInputSourcesManager *input_sources_manager)
{
GObject *object;
object = g_object_new (KIOSK_TYPE_INPUT_SOURCE_GROUP,
"input-sources-manager", input_sources_manager,
NULL);
@@ -213,121 +213,156 @@ kiosk_input_source_group_set_input_engine (KioskInputSourceGroup *self,
const char *engine_name)
{
g_debug ("KioskInputSourceGroup: Setting input engine to '%s'", engine_name);
@ -66,6 +137,8 @@ index a0c924e..6e2712f 100644
size_t number_of_layouts;
g_autofree char *layouts = NULL;
g_autofree char *variants = NULL;
+ gboolean keymap_already_set = FALSE;
+ gboolean layout_group_already_locked = FALSE;
g_debug ("KioskInputSourceGroup: Activating input source");
@ -90,16 +163,36 @@ index a0c924e..6e2712f 100644
if (!activated) {
g_debug ("KioskInputSourceGroup: Could not activate input engine '%s'", self->input_engine_name);
return FALSE;
@@ -274,60 +280,71 @@ kiosk_input_source_group_activate (KioskInputSourceGroup *self)
}
} else {
kiosk_input_engine_manager_activate_engine (self->input_engine_manager, NULL);
}
g_debug ("KioskInputSourceGroup: Setting keyboard mapping to [%s] (%s) [%s]",
layouts, variants, self->options);
- g_debug ("KioskInputSourceGroup: Setting keyboard mapping to [%s] (%s) [%s]",
- layouts, variants, self->options);
+ if (self->x_keyboard_manager != NULL) {
+ keymap_already_set = kiosk_x_keyboard_manager_keymap_is_active (self->x_keyboard_manager, (const char * const *) self->layouts->pdata, (const char * const *) self->variants->pdata, self->options);
+ layout_group_already_locked = kiosk_x_keyboard_manager_layout_group_is_locked (self->x_keyboard_manager, self->layout_index);
meta_backend_set_keymap (meta_get_backend (), layouts, variants, self->options);
meta_backend_lock_layout_group (meta_get_backend (), self->layout_index);
- meta_backend_set_keymap (meta_get_backend (), layouts, variants, self->options);
- meta_backend_lock_layout_group (meta_get_backend (), self->layout_index);
+ }
+
+ if (!keymap_already_set) {
+ g_debug ("KioskInputSourceGroup: Setting keyboard mapping to [%s] (%s) [%s]",
+ layouts, variants, self->options);
+
+ meta_backend_set_keymap (meta_get_backend (), layouts, variants, self->options);
+ }
+
+ if (!layout_group_already_locked) {
+ g_debug ("KioskInputSourceGroup: Locking layout to index %d", self->layout_index);
+ meta_backend_lock_layout_group (meta_get_backend (), self->layout_index);
+ }
+
+ if (keymap_already_set && layout_group_already_locked) {
+ g_debug ("KioskInputSourceGroup: Input source already active");
+ }
return TRUE;
}
@ -162,6 +255,58 @@ index a0c924e..6e2712f 100644
void
kiosk_input_source_group_switch_to_first_layout (KioskInputSourceGroup *self)
{
@@ -492,49 +527,51 @@ kiosk_input_source_group_get_property (GObject *object,
GValue *value,
GParamSpec *param_spec)
{
switch (property_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
break;
}
}
static void
kiosk_input_source_group_init (KioskInputSourceGroup *self)
{
g_debug ("KioskInputSourceGroup: Initializing");
self->layouts = g_ptr_array_new_full (KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS + 1, g_free);
self->variants = g_ptr_array_new_full (KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS + 1, g_free);
g_ptr_array_add (self->layouts, NULL);
g_ptr_array_add (self->variants, NULL);
}
static void
kiosk_input_source_group_constructed (GObject *object)
{
KioskInputSourceGroup *self = KIOSK_INPUT_SOURCE_GROUP (object);
G_OBJECT_CLASS (kiosk_input_source_group_parent_class)->constructed (object);
g_set_weak_pointer (&self->input_engine_manager, kiosk_input_sources_manager_get_input_engine_manager (self->input_sources_manager));
+ g_set_weak_pointer (&self->x_keyboard_manager, kiosk_input_sources_manager_get_x_keyboard_manager (self->input_sources_manager));
}
static void
kiosk_input_source_group_dispose (GObject *object)
{
KioskInputSourceGroup *self = KIOSK_INPUT_SOURCE_GROUP (object);
g_debug ("KioskInputSourceGroup: Disposing");
g_clear_pointer (&self->options, g_free);
g_clear_pointer (&self->variants, g_ptr_array_unref);
g_clear_pointer (&self->layouts, g_ptr_array_unref);
+ g_clear_weak_pointer (&self->x_keyboard_manager);
g_clear_weak_pointer (&self->input_engine_manager);
g_clear_weak_pointer (&self->input_sources_manager);
G_OBJECT_CLASS (kiosk_input_source_group_parent_class)->dispose (object);
}
diff --git a/compositor/kiosk-input-source-group.h b/compositor/kiosk-input-source-group.h
index cec8b2f..d255da4 100644
--- a/compositor/kiosk-input-source-group.h
@ -210,10 +355,10 @@ index cec8b2f..d255da4 100644
gboolean kiosk_input_source_group_switch_to_previous_layout (KioskInputSourceGroup *input_sources);
G_END_DECLS
diff --git a/compositor/kiosk-input-sources-manager.c b/compositor/kiosk-input-sources-manager.c
index 4b4ef62..c6c8c91 100644
index a1a4cfa..7bb67b0 100644
--- a/compositor/kiosk-input-sources-manager.c
+++ b/compositor/kiosk-input-sources-manager.c
@@ -1,83 +1,88 @@
@@ -1,83 +1,85 @@
#include "config.h"
#include "kiosk-input-sources-manager.h"
@ -227,9 +372,6 @@ index 4b4ef62..c6c8c91 100644
#include <meta/meta-backend.h>
#include <meta/meta-plugin.h>
+#include <meta/meta-x11-display.h>
+
+#include <X11/Xatom.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-languages.h>
@ -302,7 +444,74 @@ index 4b4ef62..c6c8c91 100644
guint property_id,
GValue *value,
GParamSpec *param_spec);
@@ -1363,60 +1368,189 @@ on_input_engine_manager_active_engine_changed (KioskInputSourcesManager *self)
@@ -690,60 +692,66 @@ on_dbus_service_handle_select_input_source (KioskInputSourcesManager *self,
static gboolean
on_dbus_service_handle_select_next_input_source (KioskInputSourcesManager *self,
GDBusMethodInvocation *invocation)
{
g_debug ("KioskService: Handling SelectNextInputSource() call");
kiosk_input_sources_manager_switch_to_next_input_source (self);
kiosk_dbus_input_sources_manager_complete_select_next_input_source (self->dbus_service, invocation);
return TRUE;
}
static gboolean
on_dbus_service_handle_select_previous_input_source (KioskInputSourcesManager *self,
GDBusMethodInvocation *invocation)
{
g_debug ("KioskService: Handling SelectPreviousInputSource() call");
kiosk_input_sources_manager_switch_to_previous_input_source (self);
kiosk_dbus_input_sources_manager_complete_select_previous_input_source (self->dbus_service, invocation);
return TRUE;
}
KioskInputEngineManager *
kiosk_input_sources_manager_get_input_engine_manager (KioskInputSourcesManager *self)
{
return self->input_engine_manager;
}
+KioskXKeyboardManager *
+kiosk_input_sources_manager_get_x_keyboard_manager (KioskInputSourcesManager *self)
+{
+ return self->x_keyboard_manager;
+}
+
void
kiosk_input_sources_manager_clear_input_sources (KioskInputSourcesManager *self)
{
g_debug ("KioskInputSourcesManager: Clearing selected keyboard mappings");
g_ptr_array_set_size (self->input_source_groups, 0);
self->input_source_groups_index = 0;
}
static void
kiosk_input_sources_manager_add_input_source_group (KioskInputSourcesManager *self,
KioskInputSourceGroup *input_source_group)
{
g_ptr_array_add (self->input_source_groups, g_object_ref (input_source_group));
}
static KioskInputSourceGroup *
kiosk_input_sources_manager_add_new_input_source_group (KioskInputSourcesManager *self,
const char *options)
{
g_autoptr (KioskInputSourceGroup) input_source_group = NULL;
g_debug ("KioskInputSourcesManager: Adding new, empty keyboard mapping with options '%s'",
options);
input_source_group = kiosk_input_source_group_new (self);
kiosk_input_source_group_set_options (input_source_group, options);
kiosk_input_sources_manager_add_input_source_group (self, input_source_group);
@@ -1340,60 +1348,180 @@ on_input_engine_manager_active_engine_changed (KioskInputSourcesManager *self)
active_input_engine = kiosk_input_engine_manager_get_active_engine (self->input_engine_manager);
@ -336,24 +545,27 @@ index 4b4ef62..c6c8c91 100644
+static void
+process_x_keyboard_manager_selected_layout_change (KioskInputSourcesManager *self)
+{
+ const char *selected_layout;
+ const char *selected_layout;
+
+ selected_layout = kiosk_x_keyboard_manager_get_selected_layout (self->x_keyboard_manager);
+ selected_layout = kiosk_x_keyboard_manager_get_selected_layout (self->x_keyboard_manager);
+
+ if (selected_layout == NULL) {
+ return;
+ }
+ if (selected_layout == NULL) {
+ return;
+ }
+
+ g_debug ("KioskInputSourcesManager: X server changed active layout to %s", selected_layout);
+ g_debug ("KioskInputSourcesManager: X server changed active layout to %s", selected_layout);
+
+ activate_input_source_group_with_layout (self, selected_layout);
+ activate_input_source_group_with_layout (self, selected_layout);
+
+ sync_dbus_service (self);
+ sync_dbus_service (self);
+}
+
+static void
+on_x_keyboard_manager_selected_layout_changed (KioskInputSourcesManager *self)
+{
+ /* We defer processing the layout change for a bit, because often in practice there is more than
+ * one layout change at the same time, and only the last one is the desired one
+ */
+ kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
+ "[kiosk-input-sources-manager] process_x_keyboard_manager_selected_layout_change",
+ self->cancellable,
@ -400,7 +612,7 @@ index 4b4ef62..c6c8c91 100644
+}
+
+static void
+process_x_keyboard_manager_layouts_change (KioskInputSourcesManager *self)
+on_x_keyboard_manager_layouts_changed (KioskInputSourcesManager *self)
+{
+ const char * const *new_layouts;
+ const char *selected_layout;
@ -433,23 +645,11 @@ index 4b4ef62..c6c8c91 100644
+}
+
+static void
+on_x_keyboard_manager_layouts_changed (KioskInputSourcesManager *self)
+{
+ kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
+ "[kiosk-input-sources-manager] process_x_keyboard_manager_layouts_change",
+ self->cancellable,
+ KIOSK_OBJECT_CALLBACK (process_x_keyboard_manager_layouts_change),
+ NULL);
+}
+
+static void
+kiosk_input_source_manager_start_x_keyboard_manager (KioskInputSourcesManager *self)
+{
+ if (meta_is_wayland_compositor ()) {
+ return;
+ }
+
+ g_debug ("KioskInputSourcesManager: Starting X Keyboard Manager");
+ self->x_keyboard_manager = kiosk_x_keyboard_manager_new (self->compositor);
+
+ g_signal_connect_object (G_OBJECT (self->x_keyboard_manager),
+ "notify::selected-layout",
+ G_CALLBACK (on_x_keyboard_manager_selected_layout_changed),
@ -492,7 +692,7 @@ index 4b4ef62..c6c8c91 100644
G_CALLBACK (on_dbus_service_handle_select_input_source),
self,
G_CONNECT_SWAPPED);
@@ -1430,63 +1564,71 @@ kiosk_input_sources_manager_handle_dbus_service (KioskInputSourcesManager *self)
@@ -1407,63 +1535,78 @@ kiosk_input_sources_manager_handle_dbus_service (KioskInputSourcesManager *self)
G_CALLBACK (on_dbus_service_handle_select_previous_input_source),
self,
G_CONNECT_SWAPPED);
@ -524,11 +724,19 @@ index 4b4ef62..c6c8c91 100644
kiosk_input_sources_manager_set_input_sources_from_session_configuration (self);
+
+ kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
+ "[kiosk-input-sources-manager] kiosk_input_source_manager_start_x_keyboard_manager",
+ self->cancellable,
+ KIOSK_OBJECT_CALLBACK (kiosk_input_source_manager_start_x_keyboard_manager ),
+ NULL);
+ /* We start the X keyboard manager after we've already loaded and locked in
+ * GSettings etc, so the session settings take precedence over xorg.conf
+ */
+ if (!meta_is_wayland_compositor ()) {
+ g_debug ("KioskInputSourcesManager: Will start X keyboard manager shortly");
+ kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
+ "[kiosk-input-sources-manager] kiosk_input_source_manager_start_x_keyboard_manager",
+ self->cancellable,
+ KIOSK_OBJECT_CALLBACK (kiosk_input_source_manager_start_x_keyboard_manager),
+ NULL);
+ } else {
+ g_debug ("KioskInputSourcesManager: Won't start X keyboard manager on wayland");
+ }
}
static void
@ -558,18 +766,59 @@ index 4b4ef62..c6c8c91 100644
kiosk_input_sources_manager_remove_key_bindings (self);
g_clear_weak_pointer (&self->dbus_service);
g_clear_weak_pointer (&self->dbus_object_manager);
+
g_clear_weak_pointer (&self->display);
g_clear_weak_pointer (&self->compositor);
G_OBJECT_CLASS (kiosk_input_sources_manager_parent_class)->dispose (object);
}
diff --git a/compositor/kiosk-input-sources-manager.h b/compositor/kiosk-input-sources-manager.h
index 0b1a738..8a44c3a 100644
--- a/compositor/kiosk-input-sources-manager.h
+++ b/compositor/kiosk-input-sources-manager.h
@@ -1,35 +1,37 @@
#pragma once
#include <glib-object.h>
#include "kiosk-input-source-group.h"
#include "kiosk-input-engine-manager.h"
+#include "kiosk-x-keyboard-manager.h"
typedef struct _KioskCompositor KioskCompositor;
G_BEGIN_DECLS
#define KIOSK_TYPE_INPUT_SOURCES_MANAGER (kiosk_input_sources_manager_get_type ())
G_DECLARE_FINAL_TYPE (KioskInputSourcesManager,
kiosk_input_sources_manager,
KIOSK, INPUT_SOURCES_MANAGER,
GObject)
KioskInputSourcesManager *kiosk_input_sources_manager_new (KioskCompositor *compositor);
KioskInputEngineManager *kiosk_input_sources_manager_get_input_engine_manager (KioskInputSourcesManager *manager);
+KioskXKeyboardManager *kiosk_input_sources_manager_get_x_keyboard_manager (KioskInputSourcesManager *manager);
void kiosk_input_sources_manager_clear_input_sources (KioskInputSourcesManager *self);
gboolean kiosk_input_sources_manager_set_input_sources_from_locales (KioskInputSourcesManager *self,
const char * const *locales,
const char *options);
gboolean kiosk_input_sources_manager_set_input_sources_from_session_configuration (KioskInputSourcesManager *manager);
void kiosk_input_sources_manager_add_layout (KioskInputSourcesManager *self,
const char *layout,
const char *options);
void kiosk_input_sources_manager_add_input_engine (KioskInputSourcesManager *self,
const char *engine_name,
const char *options);
G_END_DECLS
diff --git a/compositor/kiosk-x-keyboard-manager.c b/compositor/kiosk-x-keyboard-manager.c
new file mode 100644
index 0000000..d5c64fb
index 0000000..ad18d39
--- /dev/null
+++ b/compositor/kiosk-x-keyboard-manager.c
@@ -0,0 +1,579 @@
@@ -0,0 +1,565 @@
+#include "config.h"
+#include "kiosk-x-keyboard-manager.h"
+
@ -597,7 +846,6 @@ index 0000000..d5c64fb
+ KioskCompositor *compositor;
+ MetaBackend *backend;
+ MetaDisplay *display;
+ MetaX11Display *x11_display;
+ Display *x_server_display;
+
+ /* strong references */
@ -612,10 +860,10 @@ index 0000000..d5c64fb
+ int xkb_event_base;
+
+ size_t layout_index;
+ ssize_t pending_layout_index;
+
+ /* flags */
+ guint32 watching_x_server_root_window : 1;
+ guint32 disallow_layout_selection: 1;
+ guint32 xkb_rules_names_data_changed: 1;
+};
+
+enum
@ -775,18 +1023,6 @@ index 0000000..d5c64fb
+}
+
+static void
+kiosk_x_keyboard_manager_disallow_layout_selection (KioskXKeyboardManager *self)
+{
+ self->disallow_layout_selection = TRUE;
+}
+
+static void
+kiosk_x_keyboard_manager_allow_layout_selection (KioskXKeyboardManager *self)
+{
+ self->disallow_layout_selection = FALSE;
+}
+
+static void
+kiosk_x_keyboard_manager_set_layout_index (KioskXKeyboardManager *self,
+ size_t layout_index)
+{
@ -809,23 +1045,21 @@ index 0000000..d5c64fb
+ g_object_notify (G_OBJECT (self), "selected-layout");
+}
+
+static void
+static gboolean
+kiosk_x_keyboard_manager_read_current_layout_index (KioskXKeyboardManager *self)
+{
+ XkbStateRec xkb_state = { 0 };
+ int status;
+
+ meta_x11_error_trap_push (self->x11_display);
+ status = XkbGetState (self->x_server_display, XkbUseCoreKbd, &xkb_state);
+ meta_x11_error_trap_pop (self->x11_display);
+
+ if (status != Success) {
+ g_debug ("KioskXKeyboardManager: Could not read current layout index");
+ return;
+ return FALSE;
+ }
+ g_debug ("KioskXKeyboardManager: Current layout index: %u", xkb_state.locked_group);
+
+ kiosk_x_keyboard_manager_set_layout_index (self, xkb_state.locked_group);
+ return FALSE;
+}
+
+static gboolean
@ -855,7 +1089,7 @@ index 0000000..d5c64fb
+ OPTIONS
+ } property_value_index;
+
+ kiosk_x_keyboard_manager_allow_layout_selection (self);
+ self->xkb_rules_names_data_changed = TRUE;
+
+ g_debug ("KioskXKeyboardManager: Reading active keyboard layouts from X server");
+
@ -886,14 +1120,6 @@ index 0000000..d5c64fb
+ (GDestroyNotify) XFree,
+ NULL);
+
+ if (self->xkb_rules_names_data != NULL && g_bytes_equal (self->xkb_rules_names_data, new_xkb_rules_names_data)) {
+ g_debug ("KioskXKeyboardManager: XKB rules names data is unchanged");
+ return FALSE;
+ }
+
+ g_clear_pointer (&self->xkb_rules_names_data, g_bytes_unref);
+ self->xkb_rules_names_data = g_steal_pointer (&new_xkb_rules_names_data);
+
+ property_value_index = 0;
+ for (i = 0; i < number_of_bytes_read; i++) {
+ g_autofree char *value = g_strdup ((char *) property_values + i);
@ -912,8 +1138,8 @@ index 0000000..d5c64fb
+ g_debug ("KioskXKeyboardManager: Read variants '%s'", variants_string);
+ break;
+ case OPTIONS:
+ g_debug ("KioskXKeyboardManager: Read options '%s'", options);
+ options = g_steal_pointer (&value);
+ g_debug ("KioskXKeyboardManager: Read options '%s'", options);
+ break;
+ }
+
@ -921,6 +1147,14 @@ index 0000000..d5c64fb
+ property_value_index++;
+ }
+
+ if (self->xkb_rules_names_data != NULL && g_bytes_equal (self->xkb_rules_names_data, new_xkb_rules_names_data)) {
+ g_debug ("KioskXKeyboardManager: XKB rules names data is unchanged");
+ return FALSE;
+ }
+
+ g_clear_pointer (&self->xkb_rules_names_data, g_bytes_unref);
+ self->xkb_rules_names_data = g_steal_pointer (&new_xkb_rules_names_data);
+
+ layouts = g_strsplit (layouts_string, ",", -1);
+ variants = g_strsplit (variants_string, ",", -1);
+
@ -951,32 +1185,22 @@ index 0000000..d5c64fb
+}
+
+static void
+on_x_server_xkb_rules_names_data_changed (KioskXKeyboardManager *self)
+{
+ g_debug ("KioskXKeyboardManager: X server keyboard layouts changed");
+
+ kiosk_x_keyboard_manager_read_xkb_rules_names_data (self);
+}
+
+static void
+monitor_x_server_display_for_property_changes (KioskXKeyboardManager *self,
+ Display *x_server_display)
+monitor_x_server_display_for_changes (KioskXKeyboardManager *self)
+{
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+ XWindowAttributes attributes;
+
+ if (self->watching_x_server_root_window) {
+ return;
+ }
+
+ XGetWindowAttributes (x_server_display, self->x_server_root_window, &attributes);
+ XGetWindowAttributes (self->x_server_display, self->x_server_root_window, &attributes);
+
+ if (!(attributes.your_event_mask & PropertyChangeMask)) {
+ XSelectInput (x_server_display,
+ XSelectInput (self->x_server_display,
+ self->x_server_root_window,
+ attributes.your_event_mask | PropertyChangeMask);
+ }
+
+ self->watching_x_server_root_window = TRUE;
+ XkbQueryExtension (self->x_server_display, NULL, &self->xkb_event_base, NULL, &major, &minor);
+ self->xkb_rules_names_atom = XInternAtom (self->x_server_display, "_XKB_RULES_NAMES", False);
+}
+
+static void
@ -991,17 +1215,8 @@ index 0000000..d5c64fb
+ return;
+ }
+
+ g_debug ("KioskXKeyboardManager: XKB rules names data changed in X server");
+
+ /* We block layout index changes until we have a chance to figure out what the new layouts are
+ */
+ kiosk_x_keyboard_manager_disallow_layout_selection (self);
+
+ kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
+ "[kiosk-input-sources-manager] on_x_server_xkb_rules_names_data_changed",
+ self->cancellable,
+ KIOSK_OBJECT_CALLBACK (on_x_server_xkb_rules_names_data_changed),
+ NULL);
+ g_debug ("KioskXKeyboardManager: XKB rules names property changed in X server");
+ kiosk_x_keyboard_manager_read_xkb_rules_names_data (self);
+}
+
+static void
@ -1016,12 +1231,19 @@ index 0000000..d5c64fb
+ if (!(x_server_event->state.changed & XkbGroupStateMask)) {
+ return;
+ }
+ if (self->disallow_layout_selection) {
+ g_debug ("KioskXKeyboardManager: Ignoring layout change request to group %lu", layout_index);
+
+ /* Mutter immediately reverts all layout changes coming from
+ * the outside, so we hide the event from it.
+ */
+ x_server_event->state.changed &= ~XkbGroupLockMask;
+
+ if (self->xkb_rules_names_data_changed) {
+ g_debug ("KioskXKeyboardManager: Ignoring spurious group change following layout change");
+ self->xkb_rules_names_data_changed = FALSE;
+ return;
+
+ }
+ g_debug ("KioskXKeyboardManager: Approving keyboard group change to group %lu", layout_index);
+ meta_backend_lock_layout_group (self->backend, layout_index);
+ kiosk_x_keyboard_manager_set_layout_index (self, layout_index);
+ break;
+ }
@ -1031,7 +1253,12 @@ index 0000000..d5c64fb
+on_x_server_event (KioskXKeyboardManager *self,
+ XEvent *x_server_event)
+{
+ monitor_x_server_display_for_property_changes (self, x_server_event->xany.display);
+
+ if (self->x_server_display == NULL) {
+ self->x_server_display = x_server_event->xany.display;
+ self->x_server_root_window = DefaultRootWindow (self->x_server_display);
+ monitor_x_server_display_for_changes (self);
+ }
+
+ switch (x_server_event->type) {
+ case PropertyNotify:
@ -1062,6 +1289,8 @@ index 0000000..d5c64fb
+ return NULL;
+ }
+
+ g_debug ("KioskXKeyboardManager: Selected layout is '%s'", self->layouts[self->layout_index]);
+
+ return self->layouts[self->layout_index];
+}
+
@ -1073,20 +1302,41 @@ index 0000000..d5c64fb
+ return self->options;
+}
+
+static void
+kiosk_x_keyboard_manager_init (KioskXKeyboardManager *self)
+gboolean
+kiosk_x_keyboard_manager_keymap_is_active (KioskXKeyboardManager *self,
+ const char * const *layouts,
+ const char * const *variants,
+ const char *options)
+{
+ g_auto (GStrv) qualified_layouts = NULL;
+
+ if (g_strcmp0 (options, self->options) != 0) {
+ return FALSE;
+ }
+
+ qualified_layouts = qualify_layouts_with_variants (self, layouts, variants);
+
+ if (qualified_layouts == NULL) {
+ return FALSE;
+ }
+
+ if (!g_strv_equal ((const char * const *) qualified_layouts, (const char * const *) self->layouts)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+kiosk_x_keyboard_manager_layout_group_is_locked (KioskXKeyboardManager *self,
+ xkb_layout_index_t layout_index)
+{
+ return self->layout_index == layout_index;
+}
+
+static void
+kiosk_x_keyboard_manager_initialize_xkb_extension (KioskXKeyboardManager *self)
+kiosk_x_keyboard_manager_init (KioskXKeyboardManager *self)
+{
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+
+ XkbQueryExtension (self->x_server_display, NULL, &self->xkb_event_base, NULL, &major, &minor);
+
+ self->xkb_rules_names_atom = XInternAtom (self->x_server_display, "_XKB_RULES_NAMES", False);
+}
+
+static void
@ -1102,15 +1352,8 @@ index 0000000..d5c64fb
+
+ g_set_weak_pointer (&self->backend, meta_get_backend ());
+ g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
+ g_set_weak_pointer (&self->x11_display, meta_display_get_x11_display (self->display));
+
+ self->x_server_display = meta_x11_display_get_xdisplay (self->x11_display);
+ g_object_add_weak_pointer (G_OBJECT (self->x11_display), (gpointer *) &self->x_server_display);
+
+ self->x_server_root_window = meta_x11_display_get_xroot (self->x11_display);
+ g_object_add_weak_pointer (G_OBJECT (self->x11_display), (gpointer *) &self->x_server_root_window);
+
+ kiosk_x_keyboard_manager_initialize_xkb_extension (self);
+ self->pending_layout_index = -1;
+
+ g_signal_connect_object (G_OBJECT (self->compositor),
+ "x-server-event",
@ -1135,14 +1378,6 @@ index 0000000..d5c64fb
+ g_clear_pointer (&self->layouts, g_strfreev);
+ g_clear_pointer (&self->options, g_free);
+
+ if (self->x11_display != NULL) {
+ g_object_remove_weak_pointer (G_OBJECT (self->x11_display),
+ (gpointer *) &self->x_server_display);
+ g_object_remove_weak_pointer (G_OBJECT (self->x11_display),
+ (gpointer *) &self->x_server_root_window);
+ }
+ g_clear_weak_pointer (&self->x11_display);
+
+ g_clear_weak_pointer (&self->display);
+ g_clear_weak_pointer (&self->backend);
+ g_clear_weak_pointer (&self->compositor);
@ -1151,13 +1386,14 @@ index 0000000..d5c64fb
+}
diff --git a/compositor/kiosk-x-keyboard-manager.h b/compositor/kiosk-x-keyboard-manager.h
new file mode 100644
index 0000000..b402465
index 0000000..bae498f
--- /dev/null
+++ b/compositor/kiosk-x-keyboard-manager.h
@@ -0,0 +1,22 @@
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <glib-object.h>
+#include <xkbcommon/xkbcommon.h>
+
+typedef struct _KioskCompositor KioskCompositor;
+
@ -1175,6 +1411,12 @@ index 0000000..b402465
+const char * const *kiosk_x_keyboard_manager_get_layouts (KioskXKeyboardManager *manager);
+const char *kiosk_x_keyboard_manager_get_selected_layout (KioskXKeyboardManager *manager);
+const char *kiosk_x_keyboard_manager_get_options (KioskXKeyboardManager *manager);
+gboolean kiosk_x_keyboard_manager_keymap_is_active (KioskXKeyboardManager *manager,
+ const char * const *layouts,
+ const char * const *variants,
+ const char *options);
+gboolean kiosk_x_keyboard_manager_layout_group_is_locked (KioskXKeyboardManager *manager,
+ xkb_layout_index_t layout_index);
+
+G_END_DECLS
diff --git a/meson.build b/meson.build
@ -1244,5 +1486,5 @@ index 2b5640a..44afcea 100644
type: 'desktop'
)
--
2.31.1
2.30.2

View File

@ -12,7 +12,7 @@
Name: gnome-kiosk
Version: 40~alpha
Release: 4%{?dist}
Release: 5%{?dist}
Summary: Window management and application launching for GNOME
License: GPLv2+
@ -41,10 +41,10 @@ Requires: gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas
Patch10001: 0001-compositor-Be-less-aggressive-about-full-screening-w.patch
# https://gitlab.gnome.org/halfline/gnome-kiosk/-/merge_requests/2
Patch20001: 0001-compositor-Add-signal-for-reporting-X-server-events.patch
Patch20001: 0001-gobject-utils-Log-when-executing-deferred-tasks.patch
Patch20002: 0002-input-sources-manager-Fix-overzealous-rename-mistake.patch
Patch20003: 0003-input-sources-manager-Add-function-to-load-input-sou.patch
Patch20004: 0004-wip-Better-support-libxklavier.patch
Patch20003: 0003-compositor-Add-signal-for-reporting-X-server-events.patch
Patch20004: 0004-input-sources-manager-Support-libxklavier-managed-ke.patch
%description
GNOME Kiosk provides a desktop enviroment suitable for fixed purpose, or
@ -88,6 +88,9 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/org.gnome.Kiosk.Searc
%{_datadir}/wayland-sessions/org.gnome.Kiosk.SearchApp.Session.desktop
%changelog
* Wed Apr 21 2021 Ray Strode <rstrode@redhat.com> - 40~alpha-5
- Fix keyboard layouts getting out of sync in anaconda
* Tue Apr 20 2021 Ray Strode <rstrode@redhat.com> - 40~alpha-4
- Fix infinite loop