gnome-kiosk/0004-input-sources-manager-Support-libxklavier-managed-ke.patch

1491 lines
58 KiB
Diff
Raw Normal View History

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] input-sources-manager: Support libxklavier managed
keyboard layouts
Mutter currently doesn't allow libxklavier to change the layout out from
under it.
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 | 47 +-
compositor/kiosk-input-source-group.h | 5 +-
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 +
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..c33ca05 100644
--- a/compositor/kiosk-input-source-group.c
+++ b/compositor/kiosk-input-source-group.c
@@ -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);
g_free (self->input_engine_name);
self->input_engine_name = g_strdup (engine_name);
g_ptr_array_set_size (self->layouts, 0);
g_ptr_array_set_size (self->variants, 0);
g_ptr_array_add (self->layouts, NULL);
g_ptr_array_add (self->variants, NULL);
return TRUE;
}
const char *
kiosk_input_source_group_get_input_engine (KioskInputSourceGroup *self)
{
return self->input_engine_name;
}
void
kiosk_input_source_group_set_options (KioskInputSourceGroup *self,
const char *options)
{
g_free (self->options);
self->options = g_strdup (options);
}
+const char *
+kiosk_input_source_group_get_options (KioskInputSourceGroup *self)
+{
+ return self->options;
+}
+
gboolean
kiosk_input_source_group_activate (KioskInputSourceGroup *self)
{
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");
if (self->input_engine_name != NULL) {
kiosk_input_source_group_ensure_layout_for_input_engine (self);
}
number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);
if (number_of_layouts == 0) {
return FALSE;
}
layouts = g_strjoinv (",", (GStrv) self->layouts->pdata);
variants = g_strjoinv (",", (GStrv) self->variants->pdata);
if (self->input_engine_name != NULL) {
gboolean activated;
activated = kiosk_input_engine_manager_activate_engine (self->input_engine_manager, self->input_engine_name);
if (!activated) {
g_debug ("KioskInputSourceGroup: Could not activate input engine '%s'", self->input_engine_name);
return FALSE;
}
} 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);
+ 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);
+ }
+
+ 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;
}
static ssize_t
get_index_of_layout (KioskInputSourceGroup *self,
const char *layout_name)
{
g_auto (GStrv) layouts;
size_t i;
layouts = kiosk_input_source_group_get_layouts (self);
for (i = 0; layouts[i] != NULL; i++) {
if (g_strcmp0 (layout_name, layouts[i]) == 0) {
return (ssize_t) i;
}
}
return -1;
}
+gboolean
+kiosk_input_source_group_only_has_layouts (KioskInputSourceGroup *self,
+ const char * const *layouts_to_check)
+{
+ g_auto (GStrv) layouts;
+
+ layouts = kiosk_input_source_group_get_layouts (self);
+
+ return g_strv_equal (layouts_to_check, (const char * const *) layouts);
+}
+
gboolean
kiosk_input_source_group_switch_to_layout (KioskInputSourceGroup *self,
const char *layout_name)
{
g_autofree char *active_layout = NULL;
ssize_t layout_index;
layout_index = get_index_of_layout (self, layout_name);
if (layout_index < 0) {
return FALSE;
}
g_debug ("KioskInputSourceGroup: Switching to layout %s", layout_name);
active_layout = kiosk_input_source_group_get_selected_layout (self);
self->layout_index = layout_index;
g_debug ("KioskInputSourceGroup: Switching from layout '%s' to next layout '%s'",
active_layout, layout_name);
meta_backend_lock_layout_group (meta_get_backend (), self->layout_index);
return TRUE;
}
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
+++ b/compositor/kiosk-input-source-group.h
@@ -1,38 +1,41 @@
#pragma once
#include <glib-object.h>
typedef struct _KioskInputSourcesManager KioskInputSourcesManager;
G_BEGIN_DECLS
#define KIOSK_TYPE_INPUT_SOURCE_GROUP (kiosk_input_source_group_get_type ())
G_DECLARE_FINAL_TYPE (KioskInputSourceGroup,
kiosk_input_source_group,
KIOSK, INPUT_SOURCE_GROUP,
GObject)
KioskInputSourceGroup *kiosk_input_source_group_new (KioskInputSourcesManager *manager);
gboolean kiosk_input_source_group_add_layout (KioskInputSourceGroup *input_sources,
const char *layout,
const char *variant);
char *kiosk_input_source_group_get_selected_layout (KioskInputSourceGroup *input_sources);
char **kiosk_input_source_group_get_layouts (KioskInputSourceGroup *input_sources);
gboolean kiosk_input_source_group_set_input_engine (KioskInputSourceGroup *input_sources,
const char *engine_name);
const char *kiosk_input_source_group_get_input_engine (KioskInputSourceGroup *input_sources);
void kiosk_input_source_group_set_options (KioskInputSourceGroup *input_sources,
- const char *options);
+ const char *options);
+const char *kiosk_input_source_group_get_options (KioskInputSourceGroup *self);
gboolean kiosk_input_source_group_activate (KioskInputSourceGroup *input_sources);
+gboolean kiosk_input_source_group_only_has_layouts (KioskInputSourceGroup *self,
+ const char * const *layouts_to_check);
gboolean kiosk_input_source_group_switch_to_layout (KioskInputSourceGroup *input_sources,
const char *layout_name);
void kiosk_input_source_group_switch_to_first_layout (KioskInputSourceGroup *input_sources);
void kiosk_input_source_group_switch_to_last_layout (KioskInputSourceGroup *input_sources);
gboolean kiosk_input_source_group_switch_to_next_layout (KioskInputSourceGroup *input_sources);
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 a1a4cfa..7bb67b0 100644
--- a/compositor/kiosk-input-sources-manager.c
+++ b/compositor/kiosk-input-sources-manager.c
@@ -1,83 +1,85 @@
#include "config.h"
#include "kiosk-input-sources-manager.h"
#include <stdlib.h>
#include <string.h>
#include <xkbcommon/xkbcommon.h>
#include <meta/display.h>
#include <meta/keybindings.h>
#include <meta/util.h>
#include <meta/meta-backend.h>
#include <meta/meta-plugin.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-languages.h>
#include <libgnome-desktop/gnome-xkb-info.h>
#include "org.freedesktop.locale1.h"
#include "kiosk-compositor.h"
#include "kiosk-dbus-utils.h"
#include "kiosk-gobject-utils.h"
#include "kiosk-input-engine-manager.h"
#include "kiosk-input-source-group.h"
+#include "kiosk-x-keyboard-manager.h"
#define SD_LOCALE1_BUS_NAME "org.freedesktop.locale1"
#define SD_LOCALE1_OBJECT_PATH "/org/freedesktop/locale1"
#define KIOSK_INPUT_SOURCES_SCHEMA "org.gnome.desktop.input-sources"
#define KIOSK_INPUT_SOURCES_SETTING "sources"
#define KIOSK_INPUT_OPTIONS_SETTING "xkb-options"
#define KIOSK_INPUT_SOURCE_OBJECTS_PATH_PREFIX "/org/gnome/Kiosk/InputSources"
#define KIOSK_KEYBINDINGS_SCHEMA "org.gnome.desktop.wm.keybindings"
#define KIOSK_SWITCH_INPUT_SOURCES_KEYBINDING "switch-input-source"
#define KIOSK_SWITCH_INPUT_SOURCES_BACKWARD_KEYBINDING "switch-input-source-backward"
#define KIOSK_DBUS_INPUT_SOURCES_MANGER_INPUT_SOURCE_INTERFACE "org.gnome.Kiosk.InputSources.InputSource"
struct _KioskInputSourcesManager
{
GObject parent;
/* weak references */
KioskCompositor *compositor;
MetaDisplay *display;
KioskDBusInputSourcesManager *dbus_service;
GDBusObjectManagerServer *dbus_object_manager;
/* strong references */
GCancellable *cancellable;
KioskInputEngineManager *input_engine_manager;
+ KioskXKeyboardManager *x_keyboard_manager;
SdLocale1 *locale_proxy;
GnomeXkbInfo *xkb_info;
GSettings *input_sources_settings;
GSettings *key_binding_settings;
GPtrArray *input_source_groups;
/* state */
ssize_t input_source_groups_index;
/* flags */
guint32 overriding_configuration : 1;
};
enum
{
PROP_COMPOSITOR = 1,
NUMBER_OF_PROPERTIES
};
static GParamSpec *kiosk_input_sources_manager_properties[NUMBER_OF_PROPERTIES] = { NULL, };
G_DEFINE_TYPE (KioskInputSourcesManager, kiosk_input_sources_manager, G_TYPE_OBJECT)
static void kiosk_input_sources_manager_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *param_spec);
static void kiosk_input_sources_manager_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *param_spec);
@@ -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);
if (active_input_engine == NULL) {
g_debug ("KioskInputSourcesManager: Input engine deactivated, activating first available input source");
activate_first_available_input_source_group (self);
return;
}
activate_input_source_group_with_engine (self, active_input_engine);
}
static void
kiosk_input_sources_manager_start_input_engine_manager (KioskInputSourcesManager *self)
{
self->input_engine_manager = kiosk_input_engine_manager_new (self);
g_signal_connect_object (G_OBJECT (self->input_engine_manager),
"notify::is-loaded",
G_CALLBACK (on_input_engine_manager_is_loaded_changed),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (G_OBJECT (self->input_engine_manager),
"notify::active-engine",
G_CALLBACK (on_input_engine_manager_active_engine_changed),
self,
G_CONNECT_SWAPPED);
}
+static void
+process_x_keyboard_manager_selected_layout_change (KioskInputSourcesManager *self)
+{
+ const char *selected_layout;
+
+ selected_layout = kiosk_x_keyboard_manager_get_selected_layout (self->x_keyboard_manager);
+
+ if (selected_layout == NULL) {
+ return;
+ }
+
+ g_debug ("KioskInputSourcesManager: X server changed active layout to %s", selected_layout);
+
+ activate_input_source_group_with_layout (self, selected_layout);
+
+ 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,
+ KIOSK_OBJECT_CALLBACK (process_x_keyboard_manager_selected_layout_change),
+ NULL);
+}
+
+static gboolean
+layouts_match_selected_input_source_group (KioskInputSourcesManager *self,
+ const char * const *layouts,
+ const char *options)
+{
+ KioskInputSourceGroup *input_source_group;
+
+ g_auto (GStrv) current_layouts = NULL;
+ const char *input_source_group_options;
+ const char *input_engine_name;
+
+ input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);
2021-04-19 13:49:21 +00:00
+
+ if (input_source_group == NULL) {
+ return FALSE;
+ }
+
+ input_engine_name = kiosk_input_source_group_get_input_engine (input_source_group);
+
+ if (input_engine_name != NULL) {
+ return FALSE;
+ }
+
+ current_layouts = kiosk_input_source_group_get_layouts (input_source_group);
+
+ if (!g_strv_equal ((const char * const *) current_layouts, layouts)) {
+ return FALSE;
+ }
+
+ input_source_group_options = kiosk_input_source_group_get_options (input_source_group);
+
+ if (g_strcmp0 (input_source_group_options, options) != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+on_x_keyboard_manager_layouts_changed (KioskInputSourcesManager *self)
+{
+ const char * const *new_layouts;
+ const char *selected_layout;
+ const char *options;
+ gboolean layouts_match;
+ size_t i;
+
+ new_layouts = kiosk_x_keyboard_manager_get_layouts (self->x_keyboard_manager);
+ options = kiosk_x_keyboard_manager_get_options (self->x_keyboard_manager);
+ layouts_match = layouts_match_selected_input_source_group (self, new_layouts, options);
+
+ if (layouts_match) {
+ return;
+ }
+
+ g_debug ("KioskInputSorcesManager: X server keyboard layouts changed");
+
+ self->overriding_configuration = TRUE;
+ kiosk_input_sources_manager_clear_input_sources (self);
+
+ for (i = 0; new_layouts[i] != NULL; i++) {
+ kiosk_input_sources_manager_add_layout (self, new_layouts[i], options);
+ }
+
+ selected_layout = kiosk_x_keyboard_manager_get_selected_layout (self->x_keyboard_manager);
+
+ if (selected_layout != NULL) {
+ activate_best_available_input_source_group (self, NULL, selected_layout);
+ }
+}
+
+static void
+kiosk_input_source_manager_start_x_keyboard_manager (KioskInputSourcesManager *self)
+{
+ 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),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (G_OBJECT (self->x_keyboard_manager),
+ "notify::layouts",
+ G_CALLBACK (on_x_keyboard_manager_layouts_changed),
+ self,
+ G_CONNECT_SWAPPED);
+}
+
static void
kiosk_input_sources_manager_handle_dbus_service (KioskInputSourcesManager *self)
{
KioskService *service;
service = kiosk_compositor_get_service (self->compositor);
g_set_weak_pointer (&self->dbus_service, KIOSK_DBUS_INPUT_SOURCES_MANAGER (kiosk_service_get_input_sources_manager_skeleton (service)));
g_set_weak_pointer (&self->dbus_object_manager, kiosk_service_get_input_sources_object_manager (service));
g_signal_connect_object (G_OBJECT (self->dbus_service),
"handle-set-input-sources",
G_CALLBACK (on_dbus_service_handle_set_input_sources),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (G_OBJECT (self->dbus_service),
"handle-set-input-sources-from-locales",
G_CALLBACK (on_dbus_service_handle_set_input_sources_from_locales),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (G_OBJECT (self->dbus_service),
"handle-set-input-sources-from-session-configuration",
G_CALLBACK (on_dbus_service_handle_set_input_sources_from_session_configuration),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (G_OBJECT (self->dbus_service),
"handle-select-input-source",
G_CALLBACK (on_dbus_service_handle_select_input_source),
self,
G_CONNECT_SWAPPED);
@@ -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);
}
static void
kiosk_input_sources_manager_constructed (GObject *object)
{
KioskInputSourcesManager *self = KIOSK_INPUT_SOURCES_MANAGER (object);
g_debug ("KioskInputSourcesManager: Initializing");
G_OBJECT_CLASS (kiosk_input_sources_manager_parent_class)->constructed (object);
g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
self->cancellable = g_cancellable_new ();
self->xkb_info = gnome_xkb_info_new ();
self->input_source_groups = g_ptr_array_new_full (1, g_object_unref);
kiosk_input_sources_manager_handle_dbus_service (self);
kiosk_input_sources_manager_start_input_engine_manager (self);
kiosk_input_sources_manager_connect_to_localed (self);
kiosk_input_sources_manager_add_key_bindings (self);
kiosk_input_sources_manager_set_input_sources_from_session_configuration (self);
+
+ /* 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
kiosk_input_sources_manager_init (KioskInputSourcesManager *self)
{
}
static void
kiosk_input_sources_manager_dispose (GObject *object)
{
KioskInputSourcesManager *self = KIOSK_INPUT_SOURCES_MANAGER (object);
if (self->cancellable != NULL) {
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
}
kiosk_input_sources_manager_clear_input_sources (self);
g_clear_object (&self->input_engine_manager);
+ g_clear_object (&self->x_keyboard_manager);
g_clear_object (&self->xkb_info);
g_clear_object (&self->locale_proxy);
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..ad18d39
--- /dev/null
+++ b/compositor/kiosk-x-keyboard-manager.c
@@ -0,0 +1,565 @@
+#include "config.h"
+#include "kiosk-x-keyboard-manager.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <meta/display.h>
+#include <meta/util.h>
+
+#include <meta/meta-backend.h>
+#include <meta/meta-x11-display.h>
+#include <meta/meta-x11-errors.h>
+
+#include <X11/Xatom.h>
+#include <X11/XKBlib.h>
+
+#include "kiosk-compositor.h"
+#include "kiosk-gobject-utils.h"
+
+struct _KioskXKeyboardManager
+{
+ GObject parent;
+
+ /* weak references */
+ KioskCompositor *compositor;
+ MetaBackend *backend;
+ MetaDisplay *display;
+ Display *x_server_display;
+
+ /* strong references */
+ GCancellable *cancellable;
+ GBytes *xkb_rules_names_data;
+ char **layouts;
+ char *options;
+
+ /* state */
+ Window x_server_root_window;
+ Atom xkb_rules_names_atom;
+ int xkb_event_base;
+
+ size_t layout_index;
+ ssize_t pending_layout_index;
+
+ /* flags */
+ guint32 xkb_rules_names_data_changed: 1;
+};
+
+enum
+{
+ PROP_COMPOSITOR = 1,
+ PROP_LAYOUTS,
+ PROP_SELECTED_LAYOUT,
+ NUMBER_OF_PROPERTIES
+};
+
+static GParamSpec *kiosk_x_keyboard_manager_properties[NUMBER_OF_PROPERTIES] = { NULL, };
+
+G_DEFINE_TYPE (KioskXKeyboardManager, kiosk_x_keyboard_manager, G_TYPE_OBJECT)
+
+static void kiosk_x_keyboard_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *param_spec);
+static void kiosk_x_keyboard_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *param_spec);
+
+static void kiosk_x_keyboard_manager_constructed (GObject *object);
+static void kiosk_x_keyboard_manager_dispose (GObject *object);
+
+KioskXKeyboardManager *
+kiosk_x_keyboard_manager_new (KioskCompositor *compositor)
+{
+ GObject *object;
+
+ object = g_object_new (KIOSK_TYPE_X_KEYBOARD_MANAGER,
+ "compositor", compositor,
+ NULL);
+
+ return KIOSK_X_KEYBOARD_MANAGER (object);
+}
+
+static void
+kiosk_x_keyboard_manager_class_init (KioskXKeyboardManagerClass *x_keyboard_manager_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (x_keyboard_manager_class);
+
+ object_class->constructed = kiosk_x_keyboard_manager_constructed;
+ object_class->set_property = kiosk_x_keyboard_manager_set_property;
+ object_class->get_property = kiosk_x_keyboard_manager_get_property;
+ object_class->dispose = kiosk_x_keyboard_manager_dispose;
+
+ kiosk_x_keyboard_manager_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
+ "compositor",
+ "compositor",
+ KIOSK_TYPE_COMPOSITOR,
+ G_PARAM_CONSTRUCT_ONLY
+ | G_PARAM_WRITABLE
+ | G_PARAM_STATIC_NAME
+ | G_PARAM_STATIC_NICK
+ | G_PARAM_STATIC_BLURB);
+ kiosk_x_keyboard_manager_properties[PROP_SELECTED_LAYOUT] = g_param_spec_string ("selected-layout",
+ "selected-layout",
+ "selected-layout",
+ NULL,
+ G_PARAM_READABLE
+ | G_PARAM_STATIC_NAME
+ | G_PARAM_STATIC_NICK
+ | G_PARAM_STATIC_BLURB);
+
+ kiosk_x_keyboard_manager_properties[PROP_LAYOUTS] = g_param_spec_boxed ("layouts",
+ "layouts",
+ "layouts",
+ G_TYPE_STRV,
+ G_PARAM_READABLE
+ | G_PARAM_STATIC_NAME
+ | G_PARAM_STATIC_NICK
+ | G_PARAM_STATIC_BLURB);
+
+ g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_x_keyboard_manager_properties);
+}
+
+static void
+kiosk_x_keyboard_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *param_spec)
+{
+ KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);
+
+ switch (property_id) {
+ case PROP_COMPOSITOR:
+ g_set_weak_pointer (&self->compositor, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
+ break;
+ }
+}
+
+static void
+kiosk_x_keyboard_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *param_spec)
+{
+ KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);
+
+ switch (property_id) {
+ case PROP_SELECTED_LAYOUT:
+ g_value_set_string (value, self->layouts[self->layout_index]);
+ break;
+ case PROP_LAYOUTS:
+ g_value_set_boxed (value, self->layouts);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
+ break;
+ }
+}
+
+static char **
+qualify_layouts_with_variants (KioskXKeyboardManager *self,
+ const char * const *layouts,
+ const char * const *variants)
+{
+ size_t number_of_layouts = 0;
+ size_t number_of_variants = 0;
+ char **fully_qualified_layouts = NULL;
+
+ size_t i, j;
+
+ g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), FALSE);
+
+ number_of_layouts = g_strv_length ((GStrv) layouts);
+ number_of_variants = g_strv_length ((GStrv) variants);
+
+ if (number_of_layouts < number_of_variants) {
+ g_debug ("KioskXKeyboardManager: There is a layout variant mismatch");
+ return NULL;
+ }
+
+ fully_qualified_layouts = g_new0 (char *, number_of_layouts + 1);
+
+ for (i = 0, j = 0; layouts[i] != NULL; i++) {
+ const char *layout = layouts[i];
+ const char *variant = "";
+
+ if (variants[j] != NULL) {
+ variant = variants[j++];
+ }
+
+ if (variant[0] == '\0') {
+ fully_qualified_layouts[i] = g_strdup (layout);
+ } else {
+ fully_qualified_layouts[i] = g_strdup_printf ("%s+%s", layout, variant);
+ }
+ }
+
+ return fully_qualified_layouts;
+}
+
+static void
+kiosk_x_keyboard_manager_set_layout_index (KioskXKeyboardManager *self,
+ size_t layout_index)
+{
+ size_t number_of_layouts;
+
+ if (self->layout_index == layout_index) {
+ return;
+ }
+
+ g_debug ("KioskXKeyboardManager: X server is using layout with index %ld",
+ layout_index);
+
+ number_of_layouts = g_strv_length (self->layouts);
+
+ if (layout_index >= number_of_layouts) {
+ layout_index = 0;
+ }
+
+ self->layout_index = layout_index;
+ g_object_notify (G_OBJECT (self), "selected-layout");
+}
+
+static gboolean
+kiosk_x_keyboard_manager_read_current_layout_index (KioskXKeyboardManager *self)
+{
+ XkbStateRec xkb_state = { 0 };
+ int status;
+
+ status = XkbGetState (self->x_server_display, XkbUseCoreKbd, &xkb_state);
+
+ if (status != Success) {
2021-04-20 14:10:50 +00:00
+ g_debug ("KioskXKeyboardManager: Could not read current layout index");
+ return FALSE;
+ }
+
+ kiosk_x_keyboard_manager_set_layout_index (self, xkb_state.locked_group);
+ return FALSE;
+}
+
+static gboolean
+kiosk_x_keyboard_manager_read_xkb_rules_names_data (KioskXKeyboardManager *self)
+{
+ g_autoptr (GBytes) new_xkb_rules_names_data = NULL;
+ g_autoptr (GVariant) input_source_group = NULL;
+ size_t number_of_layouts = 0;
+ g_autofree char *layouts_string = NULL;
+ g_autofree char *variants_string = NULL;
+ g_autofree char *options = NULL;
+ g_auto (GStrv) layouts = NULL;
+ g_auto (GStrv) variants = NULL;
+ g_auto (GStrv) qualified_layouts = NULL;
+ int status;
+ Atom returned_type = 0;
+ int returned_format = 0;
+ gulong number_of_bytes_read = 0;
+ gulong number_of_bytes_unread = 0;
+ guchar *property_values;
+ size_t i;
+ enum {
+ RULES_NAME = 0,
+ MODEL,
+ LAYOUTS,
+ VARIANTS,
+ OPTIONS
+ } property_value_index;
+
+ self->xkb_rules_names_data_changed = TRUE;
2021-04-20 14:23:22 +00:00
+
+ g_debug ("KioskXKeyboardManager: Reading active keyboard layouts from X server");
+
+ status = XGetWindowProperty (self->x_server_display,
+ self->x_server_root_window,
+ self->xkb_rules_names_atom,
+ 0, 1024, FALSE, XA_STRING,
+ &returned_type,
+ &returned_format,
+ &number_of_bytes_read,
+ &number_of_bytes_unread,
+ &property_values);
+
+ if (status != Success) {
+ g_debug ("KioskXKeyboardManager: Could not read active keyboard layouts from X server");
+ return FALSE;
+ }
+
+ if (returned_type != XA_STRING ||
+ returned_format != 8 ||
+ number_of_bytes_unread != 0) {
+ g_debug ("KioskXKeyboardManager: Active keyboard layouts propery from X server is corrupted");
+ return FALSE;
+ }
+
+ new_xkb_rules_names_data = g_bytes_new_with_free_func (property_values,
+ number_of_bytes_read,
+ (GDestroyNotify) XFree,
+ NULL);
+
+ property_value_index = 0;
+ for (i = 0; i < number_of_bytes_read; i++) {
+ g_autofree char *value = g_strdup ((char *) property_values + i);
+ size_t value_length = strlen (value);
+
+ switch (property_value_index) {
+ case RULES_NAME:
+ case MODEL:
+ break;
+ case LAYOUTS:
+ layouts_string = g_steal_pointer (&value);
2021-04-20 14:10:50 +00:00
+ g_debug ("KioskXKeyboardManager: Read layouts '%s'", layouts_string);
+ break;
+ case VARIANTS:
+ variants_string = g_steal_pointer (&value);
2021-04-20 14:10:50 +00:00
+ g_debug ("KioskXKeyboardManager: Read variants '%s'", variants_string);
+ break;
+ case OPTIONS:
+ options = g_steal_pointer (&value);
+ g_debug ("KioskXKeyboardManager: Read options '%s'", options);
+ break;
+ }
+
+ i += value_length;
+ 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);
+
+ qualified_layouts = qualify_layouts_with_variants (self, (const char * const *)layouts, (const char * const *)variants);
+
+ if (qualified_layouts == NULL) {
2021-04-20 14:10:50 +00:00
+ g_debug ("KioskXKeyboardManager: Unable to qualify layouts with variants");
+ return FALSE;
+ }
+
+ number_of_layouts = g_strv_length (qualified_layouts);
+
+ if (number_of_layouts == 0) {
2021-04-20 14:10:50 +00:00
+ g_debug ("KioskXKeyboardManager: No layouts found");
+ return FALSE;
+ }
+
+ g_clear_pointer (&self->layouts, g_strfreev);
+ self->layouts = g_steal_pointer (&qualified_layouts);
+ self->options = g_steal_pointer (&options);
+
+ g_object_freeze_notify (G_OBJECT (self));
+ g_object_notify (G_OBJECT (self), "layouts");
+ kiosk_x_keyboard_manager_read_current_layout_index (self);
+ g_object_thaw_notify (G_OBJECT (self));
+
+ return TRUE;
+}
+
+static void
+monitor_x_server_display_for_changes (KioskXKeyboardManager *self)
+{
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+ XWindowAttributes attributes;
+
+ XGetWindowAttributes (self->x_server_display, self->x_server_root_window, &attributes);
+
+ if (!(attributes.your_event_mask & PropertyChangeMask)) {
+ XSelectInput (self->x_server_display,
+ self->x_server_root_window,
+ attributes.your_event_mask | PropertyChangeMask);
+ }
+
+ 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
+kiosk_x_keyboard_manager_handle_x_server_property_notify (KioskXKeyboardManager *self,
+ XPropertyEvent *x_server_event)
+{
+ if (x_server_event->window != self->x_server_root_window) {
+ return;
+ }
+
+ if (x_server_event->atom != self->xkb_rules_names_atom) {
+ return;
+ }
+
+ g_debug ("KioskXKeyboardManager: XKB rules names property changed in X server");
+ kiosk_x_keyboard_manager_read_xkb_rules_names_data (self);
+}
+
+static void
+kiosk_x_keyboard_manager_handle_xkb_event (KioskXKeyboardManager *self,
+ XkbEvent *x_server_event)
+{
+ size_t layout_index;
+
+ layout_index = XkbStateGroup (&x_server_event->state);
+ switch (x_server_event->any.xkb_type) {
+ case XkbStateNotify:
2021-04-20 14:10:50 +00:00
+ if (!(x_server_event->state.changed & XkbGroupStateMask)) {
+ return;
+ }
+
+ /* 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;
2021-04-20 14:10:50 +00:00
+ return;
+
2021-04-20 14:10:50 +00:00
+ }
+ g_debug ("KioskXKeyboardManager: Approving keyboard group change to group %lu", layout_index);
+ kiosk_x_keyboard_manager_set_layout_index (self, layout_index);
+ break;
+ }
+}
+
+static void
+on_x_server_event (KioskXKeyboardManager *self,
+ XEvent *x_server_event)
+{
+
+ 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:
+ kiosk_x_keyboard_manager_handle_x_server_property_notify (self, &x_server_event->xproperty);
+ break;
+ default:
+ if (x_server_event->type == self->xkb_event_base) {
+ kiosk_x_keyboard_manager_handle_xkb_event (self, (XkbEvent *) x_server_event);
+ }
+ break;
+ }
+}
+
+const char * const *
+kiosk_x_keyboard_manager_get_layouts (KioskXKeyboardManager *self)
+{
+ g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), NULL);
+
+ return (const char * const *) self->layouts;
+}
+
+const char *
+kiosk_x_keyboard_manager_get_selected_layout (KioskXKeyboardManager *self)
+{
+ g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), NULL);
+
+ if (self->layouts == NULL) {
+ return NULL;
+ }
+
+ g_debug ("KioskXKeyboardManager: Selected layout is '%s'", self->layouts[self->layout_index]);
+
+ return self->layouts[self->layout_index];
+}
+
+const char *
+kiosk_x_keyboard_manager_get_options (KioskXKeyboardManager *self)
+{
+ g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), NULL);
+
+ return self->options;
+}
+
+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_init (KioskXKeyboardManager *self)
+{
+}
+
+static void
+kiosk_x_keyboard_manager_constructed (GObject *object)
+{
+ KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);
+
+ g_debug ("KioskXKeyboardManager: Initializing");
+
+ G_OBJECT_CLASS (kiosk_x_keyboard_manager_parent_class)->constructed (object);
+
+ self->cancellable = g_cancellable_new ();
+
+ g_set_weak_pointer (&self->backend, meta_get_backend ());
+ g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
+
+ self->pending_layout_index = -1;
+
+ g_signal_connect_object (G_OBJECT (self->compositor),
+ "x-server-event",
+ G_CALLBACK (on_x_server_event),
+ self,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+kiosk_x_keyboard_manager_dispose (GObject *object)
+{
+ KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);
+
+ g_debug ("KioskXKeyboardManager: Disposing");
+
+ if (self->cancellable != NULL) {
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+ }
+
+ g_clear_pointer (&self->xkb_rules_names_data, g_bytes_unref);
+ g_clear_pointer (&self->layouts, g_strfreev);
+ g_clear_pointer (&self->options, g_free);
+
+ g_clear_weak_pointer (&self->display);
+ g_clear_weak_pointer (&self->backend);
+ g_clear_weak_pointer (&self->compositor);
+
+ G_OBJECT_CLASS (kiosk_x_keyboard_manager_parent_class)->dispose (object);
+}
diff --git a/compositor/kiosk-x-keyboard-manager.h b/compositor/kiosk-x-keyboard-manager.h
new file mode 100644
index 0000000..bae498f
--- /dev/null
+++ b/compositor/kiosk-x-keyboard-manager.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <glib-object.h>
+#include <xkbcommon/xkbcommon.h>
+
+typedef struct _KioskCompositor KioskCompositor;
+
+G_BEGIN_DECLS
+
+#define KIOSK_TYPE_X_KEYBOARD_MANAGER (kiosk_x_keyboard_manager_get_type ())
+
+G_DECLARE_FINAL_TYPE (KioskXKeyboardManager,
+ kiosk_x_keyboard_manager,
+ KIOSK, X_KEYBOARD_MANAGER,
+ GObject)
+
+KioskXKeyboardManager *kiosk_x_keyboard_manager_new (KioskCompositor *compositor);
+
+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
index 2b5640a..44afcea 100644
--- a/meson.build
+++ b/meson.build
@@ -86,60 +86,61 @@ sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
namespace: 'Kiosk',
interface_prefix: 'org.gnome',
annotations: [
[ dbus_interface, 'org.gtk.GDBus.C.Name', 'ShellDBusService' ]
]
)
dbus_interface_sources_map += { dbus_interface: sources }
compositor_dependencies = []
compositor_dependencies += c_compiler.find_library('m')
compositor_dependencies += dependency('gio-2.0')
compositor_dependencies += dependency('glib-2.0')
compositor_dependencies += dependency('gnome-desktop-3.0')
compositor_dependencies += dependency('gobject-2.0')
compositor_dependencies += dependency('ibus-1.0')
compositor_dependencies += dependency('mutter-cogl-8')
compositor_dependencies += dependency('mutter-cogl-pango-8')
compositor_dependencies += dependency('mutter-clutter-8')
compositor_dependencies += mutter_dependency
compositor_sources = []
compositor_sources += 'compositor/kiosk-backgrounds.c'
compositor_sources += 'compositor/kiosk-compositor.c'
compositor_sources += 'compositor/kiosk-dbus-utils.c'
compositor_sources += 'compositor/kiosk-gobject-utils.c'
compositor_sources += 'compositor/kiosk-input-sources-manager.c'
compositor_sources += 'compositor/kiosk-input-engine-manager.c'
compositor_sources += 'compositor/kiosk-input-source-group.c'
compositor_sources += 'compositor/kiosk-service.c'
compositor_sources += 'compositor/kiosk-shell-service.c'
+compositor_sources += 'compositor/kiosk-x-keyboard-manager.c'
compositor_sources += 'compositor/main.c'
foreach dbus_interface, sources: dbus_interface_sources_map
compositor_sources += sources
endforeach
executable('gnome-kiosk', compositor_sources,
dependencies: compositor_dependencies,
build_rpath: mutter_libdir,
install_rpath: mutter_libdir,
install: true
)
desktop_config_data = configuration_data()
desktop_config_data.set('bindir', bindir)
desktop_file = configure_file(
input: 'compositor/data/org.gnome.Kiosk.desktop.in.in',
output: 'org.gnome.Kiosk.desktop.in',
configuration: desktop_config_data
)
i18n.merge_file('desktop',
input: desktop_file,
output: 'org.gnome.Kiosk.desktop',
po_dir: po_dir,
install: true,
install_dir: desktop_data_dir,
type: 'desktop'
)
--
2.30.2