From 653abc0a8156ceb533186f8914aa4a9bc8437fc8 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sun, 18 Apr 2021 22:10:43 -0400 Subject: [PATCH] Make work better with Anaconda - Work with 3rd party keyboard layout selectors - Be less aggressive about fullscreening windows --- ...signal-for-reporting-X-server-events.patch | 229 ++++ ...ss-aggressive-about-full-screening-w.patch | 228 ++++ ...nager-Fix-overzealous-rename-mistake.patch | 188 +++ ...nager-Add-function-to-load-input-sou.patch | 219 +++ 0004-wip-Better-support-libxklavier.patch | 1210 +++++++++++++++++ gnome-kiosk.spec | 15 +- 6 files changed, 2088 insertions(+), 1 deletion(-) create mode 100644 0001-compositor-Add-signal-for-reporting-X-server-events.patch create mode 100644 0001-compositor-Be-less-aggressive-about-full-screening-w.patch create mode 100644 0002-input-sources-manager-Fix-overzealous-rename-mistake.patch create mode 100644 0003-input-sources-manager-Add-function-to-load-input-sou.patch create mode 100644 0004-wip-Better-support-libxklavier.patch diff --git a/0001-compositor-Add-signal-for-reporting-X-server-events.patch b/0001-compositor-Add-signal-for-reporting-X-server-events.patch new file mode 100644 index 0000000..3e11d0e --- /dev/null +++ b/0001-compositor-Add-signal-for-reporting-X-server-events.patch @@ -0,0 +1,229 @@ +From e27d9527fa03be29ad030634ab3b5de652527d81 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 15 Apr 2021 13:28:00 -0400 +Subject: [PATCH 1/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 +under it. + +As a first step toward fixing that problem, this commit adds a +new signal "x-server-event" to KioskCompositor, so that the +InputSourcesManager can watch for root window property changes. +--- + compositor/kiosk-compositor.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c +index b3cd10f..a8ecf5f 100644 +--- a/compositor/kiosk-compositor.c ++++ b/compositor/kiosk-compositor.c +@@ -7,60 +7,67 @@ + #include + + #include + #include + #include + #include + #include + + #include "kiosk-backgrounds.h" + #include "kiosk-input-sources-manager.h" + #include "kiosk-service.h" + + #include "org.gnome.DisplayManager.Manager.h" + + struct _KioskCompositor + { + MetaPlugin parent; + + /* weak references */ + MetaDisplay *display; + ClutterBackend *backend; + ClutterActor *stage; + + /* strong references */ + GCancellable *cancellable; + KioskBackgrounds *backgrounds; + KioskInputSourcesManager *input_sources_manager; + KioskService *service; + }; + ++enum { ++ X_SERVER_EVENT, ++ NUMBER_OF_SIGNALS ++}; ++ ++static guint signals [NUMBER_OF_SIGNALS] = { 0, }; ++ + G_DEFINE_TYPE (KioskCompositor, kiosk_compositor, META_TYPE_PLUGIN) + + static void kiosk_compositor_dispose (GObject *object); + + static void + kiosk_compositor_dispose (GObject *object) + { + KioskCompositor *self = KIOSK_COMPOSITOR (object); + + if (self->cancellable != NULL) { + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + } + + g_clear_weak_pointer (&self->stage); + g_clear_weak_pointer (&self->display); + g_clear_weak_pointer (&self->backend); + + g_clear_object (&self->backgrounds); + + G_OBJECT_CLASS (kiosk_compositor_parent_class)->dispose (object); + } + + static void + register_with_display_manager (KioskCompositor *self) + { + g_autoptr (GDBusConnection) system_bus = NULL; + g_autoptr (GdmManager) display_manager = NULL; + GVariantBuilder builder; + g_autoptr (GError) error = NULL; +@@ -267,62 +274,64 @@ kiosk_compositor_show_tile_preview (MetaPlugin *plugin, + g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->show_tile_preview == NULL); + } + + static void + kiosk_compositor_hide_tile_preview (MetaPlugin *plugin) + { + g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->hide_tile_preview == NULL); + } + + static void + kiosk_compositor_show_window_menu (MetaPlugin *plugin, + MetaWindow *window, + MetaWindowMenuType menu, + int x, + int y) + { + g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->show_window_menu == NULL); + } + + static void + kiosk_compositor_show_window_menu_for_rect (MetaPlugin *plugin, + MetaWindow *window, + MetaWindowMenuType menu, + MetaRectangle *rect) + { + g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->show_window_menu_for_rect == NULL); + } + + static gboolean + kiosk_compositor_xevent_filter (MetaPlugin *plugin, +- XEvent *xev) ++ XEvent *x_server_event) + { ++ KioskCompositor *self = KIOSK_COMPOSITOR (plugin); ++ g_signal_emit (G_OBJECT (self), signals[X_SERVER_EVENT], 0, x_server_event); + return FALSE; + } + + static gboolean + kiosk_compositor_keybinding_filter (MetaPlugin *plugin, + MetaKeyBinding *binding) + { + return FALSE; + } + + static void + kiosk_compositor_confirm_display_change (MetaPlugin *plugin) + { + KioskCompositor *self = KIOSK_COMPOSITOR (plugin); + + meta_plugin_complete_display_change (META_PLUGIN (self), TRUE); + } + + static const MetaPluginInfo info = { + .name = "GNOME Kiosk", + .version = VERSION, + .author = "Various", + .license = "GPLv2+", + .description = "Provides Kiosk compositor plugin for mutter" + }; + + static const MetaPluginInfo * + kiosk_compositor_plugin_info (MetaPlugin *plugin) + { + +@@ -358,60 +367,71 @@ kiosk_compositor_class_init (KioskCompositorClass *compositor_class) + + plugin_class->start = kiosk_compositor_start; + plugin_class->map = kiosk_compositor_map; + plugin_class->minimize = kiosk_compositor_minimize; + plugin_class->unminimize = kiosk_compositor_unminimize; + plugin_class->size_changed = kiosk_compositor_size_changed; + plugin_class->size_change = kiosk_compositor_size_change; + plugin_class->destroy = kiosk_compositor_destroy; + + plugin_class->switch_workspace = kiosk_compositor_switch_workspace; + + plugin_class->kill_window_effects = kiosk_compositor_kill_window_effects; + plugin_class->kill_switch_workspace = kiosk_compositor_kill_switch_workspace; + + plugin_class->show_tile_preview = kiosk_compositor_show_tile_preview; + plugin_class->hide_tile_preview = kiosk_compositor_hide_tile_preview; + plugin_class->show_window_menu = kiosk_compositor_show_window_menu; + plugin_class->show_window_menu_for_rect = kiosk_compositor_show_window_menu_for_rect; + + plugin_class->xevent_filter = kiosk_compositor_xevent_filter; + plugin_class->keybinding_filter = kiosk_compositor_keybinding_filter; + + plugin_class->confirm_display_change = kiosk_compositor_confirm_display_change; + + plugin_class->plugin_info = kiosk_compositor_plugin_info; + + plugin_class->create_close_dialog = kiosk_compositor_create_close_dialog; + plugin_class->create_inhibit_shortcuts_dialog = kiosk_compositor_create_inhibit_shortcuts_dialog; + + plugin_class->locate_pointer = kiosk_compositor_locate_pointer; ++ ++ signals [X_SERVER_EVENT] = ++ g_signal_new ("x-server-event", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_LAST, ++ 0, ++ NULL, ++ NULL, ++ g_cclosure_marshal_VOID__POINTER, ++ G_TYPE_NONE, ++ 1, G_TYPE_POINTER); + } + + static void + kiosk_compositor_init (KioskCompositor *compositor) + { + g_debug ("KioskCompositor: Initializing"); + } + + KioskBackgrounds * + kiosk_compositor_get_backgrounds (KioskCompositor *self) + { + g_return_val_if_fail (KIOSK_IS_COMPOSITOR (self), NULL); + + return KIOSK_BACKGROUNDS (self->backgrounds); + } + + KioskInputSourcesManager * + kiosk_compositor_get_input_sources_manager (KioskCompositor *self) + { + g_return_val_if_fail (KIOSK_IS_COMPOSITOR (self), NULL); + + return KIOSK_INPUT_SOURCES_MANAGER (self->input_sources_manager); + } + + KioskService * + kiosk_compositor_get_service (KioskCompositor *self) + { + g_return_val_if_fail (KIOSK_IS_COMPOSITOR (self), NULL); + + return KIOSK_SERVICE (self->service); +-- +2.30.2 + diff --git a/0001-compositor-Be-less-aggressive-about-full-screening-w.patch b/0001-compositor-Be-less-aggressive-about-full-screening-w.patch new file mode 100644 index 0000000..b593937 --- /dev/null +++ b/0001-compositor-Be-less-aggressive-about-full-screening-w.patch @@ -0,0 +1,228 @@ +From 348cb4fda7da06da3194a784a97946364dd3182b Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 15 Apr 2021 13:00:16 -0400 +Subject: [PATCH] compositor: Be less aggressive about full screening windows + +It's common for kiosk type applications to have dialogs and utility +windows that shouldn't get fullscreen. + +This commit tries to be a little less aggressive above fullscreening +windows. Now we assume only the first window is "the application" and +subsequent windows are auxillary and should be layered on top. +--- + compositor/kiosk-compositor.c | 78 +++++++++++++++++++++++++++++++---- + 1 file changed, 70 insertions(+), 8 deletions(-) + +diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c +index a8ecf5f..14f5de3 100644 +--- a/compositor/kiosk-compositor.c ++++ b/compositor/kiosk-compositor.c +@@ -1,43 +1,45 @@ + #include "config.h" + #include "kiosk-compositor.h" + + #include + #include + + #include + + #include + #include ++#include + #include + #include + #include ++#include + + #include "kiosk-backgrounds.h" + #include "kiosk-input-sources-manager.h" + #include "kiosk-service.h" + + #include "org.gnome.DisplayManager.Manager.h" + + struct _KioskCompositor + { + MetaPlugin parent; + + /* weak references */ + MetaDisplay *display; + ClutterBackend *backend; + ClutterActor *stage; + + /* strong references */ + GCancellable *cancellable; + KioskBackgrounds *backgrounds; + KioskInputSourcesManager *input_sources_manager; + KioskService *service; + }; + + enum { + X_SERVER_EVENT, + NUMBER_OF_SIGNALS + }; + + static guint signals [NUMBER_OF_SIGNALS] = { 0, }; + +@@ -150,91 +152,151 @@ static void + kiosk_compositor_minimize (MetaPlugin *plugin, + MetaWindowActor *actor) + { + meta_plugin_minimize_completed (plugin, actor); + } + + static void + kiosk_compositor_unminimize (MetaPlugin *plugin, + MetaWindowActor *actor) + { + meta_plugin_unminimize_completed (plugin, actor); + } + + static void + kiosk_compositor_size_changed (MetaPlugin *plugin, + MetaWindowActor *actor) + { + g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->size_changed == NULL); + } + + static void + kiosk_compositor_size_change (MetaPlugin *plugin, + MetaWindowActor *actor, + MetaSizeChange which_change, + MetaRectangle *old_frame_rect, + MetaRectangle *old_buffer_rect) + { + g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->size_change == NULL); + } + ++static gboolean ++kiosk_compositor_wants_window_fullscreen (KioskCompositor *self, ++ MetaWindow *window) ++{ ++ MetaWindowType window_type; ++ g_autoptr (GList) windows = NULL; ++ GList *node; ++ ++ if (!meta_window_allows_resize (window)) { ++ g_debug ("KioskCompositor: Window does not allow resizes"); ++ return FALSE; ++ } ++ ++ if (meta_window_is_override_redirect (window)) { ++ g_debug ("KioskCompositor: Window is override redirect"); ++ return FALSE; ++ } ++ ++ window_type = meta_window_get_window_type (window); ++ ++ if (window_type != META_WINDOW_NORMAL) { ++ g_debug ("KioskCompositor: Window is not normal"); ++ return FALSE; ++ } ++ ++ windows = meta_display_get_tab_list (self->display, META_TAB_LIST_NORMAL_ALL, NULL); ++ ++ for (node = windows; node != NULL; node = node->next) { ++ MetaWindow *existing_window = node->data; ++ ++ if (meta_window_is_fullscreen (existing_window)) { ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++static gboolean ++kiosk_compositor_wants_window_above (KioskCompositor *self, ++ MetaWindow *window) ++{ ++ if (meta_window_is_screen_sized (window)) { ++ return FALSE; ++ } ++ ++ if (meta_window_is_monitor_sized (window)) { ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + static void + on_faded_in (KioskCompositor *self, + ClutterTransition *transition) + { + MetaWindowActor *actor = g_object_get_data (G_OBJECT (transition), "actor"); +- MetaWindow *window; +- +- window = meta_window_actor_get_meta_window (actor); +- +- if (!meta_window_allows_resize (window) && !meta_window_is_override_redirect (window)) { +- meta_window_make_above (window); +- } + + meta_plugin_map_completed (META_PLUGIN (self), actor); + } + + static void + kiosk_compositor_map (MetaPlugin *plugin, + MetaWindowActor *actor) + { + KioskCompositor *self = KIOSK_COMPOSITOR (plugin); + MetaWindow *window; + ClutterTransition *fade_in_transition; + int easing_duration; + + window = meta_window_actor_get_meta_window (actor); + +- if (meta_window_allows_resize (window)) { ++ if (kiosk_compositor_wants_window_fullscreen (self, window)) { ++ g_debug ("KioskCompositor: Mapping window that does need to be fullscreened"); + meta_window_make_fullscreen (window); + easing_duration = 3000; + } else { ++ ClutterActor *window_group; ++ ++ g_debug ("KioskCompositor: Mapping window that does not need to be fullscreened"); ++ window_group = meta_get_top_window_group_for_display (self->display); ++ ++ if (kiosk_compositor_wants_window_above (self, window)) { ++ g_object_ref (G_OBJECT (actor)); ++ clutter_actor_remove_child (clutter_actor_get_parent (CLUTTER_ACTOR (actor)), CLUTTER_ACTOR (actor)); ++ clutter_actor_add_child (window_group, CLUTTER_ACTOR (actor)); ++ clutter_actor_set_child_below_sibling (window_group, CLUTTER_ACTOR (actor), NULL); ++ g_object_unref (G_OBJECT (actor)); ++ } ++ + easing_duration = 500; + } + + clutter_actor_show (self->stage); + clutter_actor_show (CLUTTER_ACTOR (actor)); + + clutter_actor_set_opacity (CLUTTER_ACTOR (actor), 0); + + clutter_actor_save_easing_state (CLUTTER_ACTOR (actor)); + clutter_actor_set_easing_duration (CLUTTER_ACTOR (actor), easing_duration); + clutter_actor_set_easing_mode (CLUTTER_ACTOR (actor), CLUTTER_EASE_IN_OUT_QUINT); + clutter_actor_set_opacity (CLUTTER_ACTOR (actor), 255); + fade_in_transition = clutter_actor_get_transition (CLUTTER_ACTOR (actor), "opacity"); + clutter_actor_restore_easing_state (CLUTTER_ACTOR (actor)); + + g_object_set_data (G_OBJECT (fade_in_transition), "actor", actor); + + g_signal_connect_object (G_OBJECT (fade_in_transition), + "completed", + G_CALLBACK (on_faded_in), + self, + G_CONNECT_SWAPPED); + } + + static void + kiosk_compositor_destroy (MetaPlugin *plugin, + MetaWindowActor *actor) + { + KioskCompositor *self = KIOSK_COMPOSITOR (plugin); + +-- +2.30.2 + diff --git a/0002-input-sources-manager-Fix-overzealous-rename-mistake.patch b/0002-input-sources-manager-Fix-overzealous-rename-mistake.patch new file mode 100644 index 0000000..24e1fb7 --- /dev/null +++ b/0002-input-sources-manager-Fix-overzealous-rename-mistake.patch @@ -0,0 +1,188 @@ +From dcda260069ff811dc46a9ab0524eab273275206f Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 15 Apr 2021 14:39:55 -0400 +Subject: [PATCH 2/4] input-sources-manager: Fix overzealous rename mistake + +At some point during development something called +KioskInputSources got renamed to KioskInputSourceGroup. + +Unfortunately, my sed-fu was weak and I renamed things it shouldn't. + +This commit fixes the errors. +--- + compositor/kiosk-input-sources-manager.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/compositor/kiosk-input-sources-manager.c b/compositor/kiosk-input-sources-manager.c +index 58d7a4c..a1a4cfa 100644 +--- a/compositor/kiosk-input-sources-manager.c ++++ b/compositor/kiosk-input-sources-manager.c +@@ -1,60 +1,60 @@ + #include "config.h" + #include "kiosk-input-sources-manager.h" + + #include + #include + + #include + #include + #include + #include + + #include + #include + + #define GNOME_DESKTOP_USE_UNSTABLE_API + #include + #include + + #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" + + #define SD_LOCALE1_BUS_NAME "org.freedesktop.locale1" + #define SD_LOCALE1_OBJECT_PATH "/org/freedesktop/locale1" + +-#define KIOSK_INPUT_SOURCE_GROUP_SCHEMA "org.gnome.desktop.input-sources" +-#define KIOSK_INPUT_SOURCE_GROUP_SETTING "sources" ++#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; + SdLocale1 *locale_proxy; + GnomeXkbInfo *xkb_info; + GSettings *input_sources_settings; + GSettings *key_binding_settings; + GPtrArray *input_source_groups; + + /* state */ +@@ -913,94 +913,94 @@ kiosk_input_sources_manager_set_input_sources_from_system_configuration (KioskIn + + 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); + } + + gboolean + kiosk_input_sources_manager_set_input_sources_from_session_configuration (KioskInputSourcesManager *self) + { +- g_autoptr (GVariant) input_source_group = NULL; ++ g_autoptr (GVariant) input_sources = NULL; + g_auto (GStrv) options = NULL; +- gboolean input_source_group_active; ++ gboolean input_sources_active; + + g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE); + + g_debug ("KioskInputSourcesManager: Setting input sources from session configuration"); + + self->overriding_configuration = FALSE; + + if (self->input_sources_settings == NULL) { +- self->input_sources_settings = g_settings_new (KIOSK_INPUT_SOURCE_GROUP_SCHEMA); ++ self->input_sources_settings = g_settings_new (KIOSK_INPUT_SOURCES_SCHEMA); + + g_signal_connect_object (G_OBJECT (self->input_sources_settings), +- "changed::" KIOSK_INPUT_SOURCE_GROUP_SETTING, ++ "changed::" KIOSK_INPUT_SOURCES_SETTING, + G_CALLBACK (on_session_input_sources_setting_changed), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (G_OBJECT (self->input_sources_settings), + "changed::" KIOSK_INPUT_OPTIONS_SETTING, + G_CALLBACK (on_session_input_sources_setting_changed), + self, + G_CONNECT_SWAPPED); + } + + + options = g_settings_get_strv (self->input_sources_settings, KIOSK_INPUT_OPTIONS_SETTING); + +- input_source_group = g_settings_get_value (self->input_sources_settings, +- KIOSK_INPUT_SOURCE_GROUP_SETTING); ++ input_sources = g_settings_get_value (self->input_sources_settings, ++ KIOSK_INPUT_SOURCES_SETTING); + +- input_source_group_active = kiosk_input_sources_manager_set_input_sources (self, input_source_group, (const char * const *) options); ++ input_sources_active = kiosk_input_sources_manager_set_input_sources (self, input_sources, (const char * const *) options); + +- if (!input_source_group_active) { ++ if (!input_sources_active) { + g_debug ("KioskInputSourcesManager: Session has no valid configured input sources"); + return kiosk_input_sources_manager_set_input_sources_from_system_configuration (self); + } + + return TRUE; + } + + gboolean + kiosk_input_sources_manager_set_input_sources_from_locales (KioskInputSourcesManager *self, + const char * const *locales, + const char *options) + { + KioskInputSourceGroup *old_input_source_group; + g_autofree char *old_selected_layout = NULL; + g_autofree char *old_input_engine = NULL; + g_autofree char *locales_string = NULL; + gboolean input_source_group_active; + + g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE); + g_return_val_if_fail (locales != NULL, FALSE); + + locales_string = g_strjoinv (",", (GStrv) locales); + + g_debug ("KioskInputSourcesManager: Setting keymap from locales '%s'", + locales_string); + + self->overriding_configuration = TRUE; + + old_input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self); + +-- +2.30.2 + diff --git a/0003-input-sources-manager-Add-function-to-load-input-sou.patch b/0003-input-sources-manager-Add-function-to-load-input-sou.patch new file mode 100644 index 0000000..bc92e1d --- /dev/null +++ b/0003-input-sources-manager-Add-function-to-load-input-sou.patch @@ -0,0 +1,219 @@ +From 3acb4e6e52c183eb756b61880e320fa3af639f89 Mon Sep 17 00:00:00 2001 +From: Ray Strode +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.30.2 + diff --git a/0004-wip-Better-support-libxklavier.patch b/0004-wip-Better-support-libxklavier.patch new file mode 100644 index 0000000..209603a --- /dev/null +++ b/0004-wip-Better-support-libxklavier.patch @@ -0,0 +1,1210 @@ +From 09b90bb8fcdcc2a15ef5d3dcc0a0eaecdb8be112 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 15 Apr 2021 14:43:17 -0400 +Subject: [PATCH 4/4] wip! Better support libxklavier + +Mutter currently doesn't allow libxklavier to change the group out from +under it. + +This commit fixes that, but also makes sure that current layout state +stays in sync with X server state. +--- + compositor/kiosk-input-source-group.c | 17 + + compositor/kiosk-input-source-group.h | 5 +- + compositor/kiosk-input-sources-manager.c | 137 ++++++ + compositor/kiosk-x-keyboard-manager.c | 546 +++++++++++++++++++++++ + compositor/kiosk-x-keyboard-manager.h | 22 + + meson.build | 1 + + 6 files changed, 727 insertions(+), 1 deletion(-) + 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 +--- 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, + 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; + + 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; +@@ -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); + + meta_backend_set_keymap (meta_get_backend (), layouts, variants, self->options); + meta_backend_lock_layout_group (meta_get_backend (), self->layout_index); + + 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) + { +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 + + 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 4b4ef62..2015887 100644 +--- a/compositor/kiosk-input-sources-manager.c ++++ b/compositor/kiosk-input-sources-manager.c +@@ -1,83 +1,88 @@ + #include "config.h" + #include "kiosk-input-sources-manager.h" + + #include + #include + + #include + #include + #include + #include + + #include + #include ++#include ++ ++#include + + #define GNOME_DESKTOP_USE_UNSTABLE_API + #include + #include + + #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); +@@ -1363,60 +1368,184 @@ 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) ++{ ++ 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); ++ 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 ++process_x_keyboard_manager_layouts_change (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 ++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; ++ } ++ ++ 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); +@@ -1430,63 +1559,71 @@ 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); ++ ++ 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); + } + + 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-x-keyboard-manager.c b/compositor/kiosk-x-keyboard-manager.c +new file mode 100644 +index 0000000..94b8f0b +--- /dev/null ++++ b/compositor/kiosk-x-keyboard-manager.c +@@ -0,0 +1,546 @@ ++#include "config.h" ++#include "kiosk-x-keyboard-manager.h" ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "kiosk-compositor.h" ++#include "kiosk-gobject-utils.h" ++ ++struct _KioskXKeyboardManager ++{ ++ GObject parent; ++ ++ /* weak references */ ++ KioskCompositor *compositor; ++ MetaBackend *backend; ++ MetaDisplay *display; ++ MetaX11Display *x11_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; ++ ++ /* flags */ ++ guint32 watching_x_server_root_window : 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 void ++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) { ++ return; ++ } ++ ++ kiosk_x_keyboard_manager_set_layout_index (self, xkb_state.locked_group); ++} ++ ++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; ++ ++ 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); ++ ++ 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); ++ size_t value_length = strlen (value); ++ ++ switch (property_value_index) { ++ case RULES_NAME: ++ case MODEL: ++ break; ++ case LAYOUTS: ++ layouts_string = g_steal_pointer (&value); ++ break; ++ case VARIANTS: ++ variants_string = g_steal_pointer (&value); ++ break; ++ case OPTIONS: ++ options = g_steal_pointer (&value); ++ break; ++ } ++ ++ i += value_length; ++ property_value_index++; ++ } ++ ++ 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) { ++ return FALSE; ++ } ++ ++ number_of_layouts = g_strv_length (qualified_layouts); ++ ++ if (number_of_layouts == 0) { ++ 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 ++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) ++{ ++ XWindowAttributes attributes; ++ ++ if (self->watching_x_server_root_window) { ++ return; ++ } ++ ++ XGetWindowAttributes (x_server_display, self->x_server_root_window, &attributes); ++ ++ if (!(attributes.your_event_mask & PropertyChangeMask)) { ++ XSelectInput (x_server_display, ++ self->x_server_root_window, ++ attributes.your_event_mask | PropertyChangeMask); ++ } ++ ++ self->watching_x_server_root_window = TRUE; ++} ++ ++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 data changed in X server"); ++ 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); ++} ++ ++static void ++kiosk_x_keyboard_manager_handle_xkb_event (KioskXKeyboardManager *self, ++ XkbEvent *x_server_event) ++{ ++ g_debug ("KioskXKeyboardManager: Got XKB event"); ++ size_t layout_index; ++ ++ layout_index = XkbStateGroup (&x_server_event->state); ++ switch (x_server_event->any.xkb_type) { ++ case XkbStateNotify: ++ 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; ++ } ++} ++ ++static void ++on_x_server_event (KioskXKeyboardManager *self, ++ XEvent *x_server_event) ++{ ++ monitor_x_server_display_for_property_changes (self, x_server_event->xany.display); ++ ++ 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; ++ } ++ ++ 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; ++} ++ ++static void ++kiosk_x_keyboard_manager_init (KioskXKeyboardManager *self) ++{ ++} ++ ++static void ++kiosk_x_keyboard_manager_initialize_xkb_extension (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 ++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))); ++ 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); ++ ++ 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); ++ ++ 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); ++ ++ 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..b402465 +--- /dev/null ++++ b/compositor/kiosk-x-keyboard-manager.h +@@ -0,0 +1,22 @@ ++#pragma once ++ ++#include ++ ++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); ++ ++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 + diff --git a/gnome-kiosk.spec b/gnome-kiosk.spec index 69c1d2a..fe97dde 100644 --- a/gnome-kiosk.spec +++ b/gnome-kiosk.spec @@ -12,7 +12,7 @@ Name: gnome-kiosk Version: 40~alpha -Release: 1%{?dist} +Release: 2%{?dist} Summary: Window management and application launching for GNOME License: GPLv2+ @@ -37,6 +37,15 @@ BuildRequires: meson Requires: gnome-settings-daemon%{?_isa} >= %{gnome_settings_daemon_version} Requires: gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas_version} +# https://gitlab.gnome.org/halfline/gnome-kiosk/-/merge_requests/1 +Patch10001: 0001-compositor-Add-signal-for-reporting-X-server-events.patch + +# https://gitlab.gnome.org/halfline/gnome-kiosk/-/merge_requests/2 +Patch20001: 0001-compositor-Be-less-aggressive-about-full-screening-w.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 + %description GNOME Kiosk provides a desktop enviroment suitable for fixed purpose, or single application deployments like wall displays and point-of-sale systems. @@ -79,6 +88,10 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/org.gnome.Kiosk.Searc %{_datadir}/wayland-sessions/org.gnome.Kiosk.SearchApp.Session.desktop %changelog +* Sun Apr 18 2021 Ray Strode - 40~alpha-2 +- Work with 3rd party keyboard layout selectors +- Be less aggressive about fullscreening windows + * Mon Apr 12 2021 Ray Strode - 40~alpha-1 - Initial import