summaryrefslogtreecommitdiffstats
path: root/debian/patches/keyboard-Correctly-update-labels-for-IBus-engines.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/keyboard-Correctly-update-labels-for-IBus-engines.patch')
-rw-r--r--debian/patches/keyboard-Correctly-update-labels-for-IBus-engines.patch189
1 files changed, 189 insertions, 0 deletions
diff --git a/debian/patches/keyboard-Correctly-update-labels-for-IBus-engines.patch b/debian/patches/keyboard-Correctly-update-labels-for-IBus-engines.patch
new file mode 100644
index 0000000..3019576
--- /dev/null
+++ b/debian/patches/keyboard-Correctly-update-labels-for-IBus-engines.patch
@@ -0,0 +1,189 @@
+From: Simon McVittie <smcv@debian.org>
+Date: Mon, 6 Mar 2023 22:23:28 +0000
+Subject: keyboard: Correctly update labels for IBus engines
+
+After the port from GTK 3 to 4, in general there's an additional level
+of indirection: the children of priv->input_list are GtkListBoxRow
+objects containing the widget whose user-data is the InputWidget. This
+means we didn't find the InputWidget and therefore couldn't update its
+display name.
+
+Unfortunately, there is one exception to the rule that every child
+of a GtkListBox is a GtkListBoxRow: the placeholder object, in our
+case priv->no_results, is not wrapped in a GtkListBoxRow (see also
+GNOME/gtk#4523). This means that walking the GtkWidget tree seems rather
+fragile: it's difficult to tell whether each child of the GtkListBox
+is a GtkListBoxRow, or the placeholder object priv->no_results, or
+some third type of object that could be added by a future GTK version
+(particularly since there is no particular type-safety here).
+
+Instead of walking the widget tree, maintain our own parallel list of
+known keyboard layouts and other input methods. For this list, we can
+safely assert that every item is something that we put there, with the
+invariant that it's a GtkBox with an InputWidget attached.
+
+This means that we can reliably find the InputWidget, and update its
+associated display name.
+
+Fixes: ad500afc "keyboard: Port to GTK4"
+Bug: https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/180
+Signed-off-by: Simon McVittie <smcv@debian.org>
+Bug-Debian: https://bugs.debian.org/1032382
+Forwarded: https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/180
+---
+ .../pages/keyboard/cc-input-chooser.c | 56 ++++++++++++----------
+ 1 file changed, 31 insertions(+), 25 deletions(-)
+
+diff --git a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
+index 2dd58e9..ae8f2d7 100644
+--- a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
++++ b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
+@@ -50,6 +50,7 @@ struct _CcInputChooserPrivate
+ {
+ GtkWidget *filter_entry;
+ GtkWidget *input_list;
++ GPtrArray *input_widget_boxes;
+ GHashTable *inputs;
+
+ GtkWidget *no_results;
+@@ -96,6 +97,11 @@ typedef struct {
+ gboolean is_extra;
+ } InputWidget;
+
++/*
++ * Invariant: for each box in priv->input_widget_boxes,
++ * get_input_widget (row) is non-null and
++ * get_input_widget (row)->box == box
++ */
+ static InputWidget *
+ get_input_widget (GtkWidget *widget)
+ {
+@@ -258,21 +264,20 @@ static void
+ sync_all_checkmarks (CcInputChooser *chooser)
+ {
+ CcInputChooserPrivate *priv;
+- GtkWidget *row;
+ gboolean invalidate = FALSE;
++ gsize i;
+
+ priv = cc_input_chooser_get_instance_private (chooser);
+- row = gtk_widget_get_first_child (priv->input_list);
+- while (row) {
++
++ for (i = 0; i < priv->input_widget_boxes->len; i++) {
+ InputWidget *widget;
+ GtkWidget *child;
+ gboolean should_be_visible;
+
+- child = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (row));
++ child = g_ptr_array_index (priv->input_widget_boxes, i);
+ widget = get_input_widget (child);
+-
+- if (widget == NULL)
+- break;
++ g_assert (widget != NULL);
++ g_assert (widget->box == child);
+
+ if (priv->id == NULL || priv->type == NULL)
+ should_be_visible = FALSE;
+@@ -287,8 +292,6 @@ sync_all_checkmarks (CcInputChooser *chooser)
+ widget->is_extra = FALSE;
+ invalidate = TRUE;
+ }
+-
+- row = gtk_widget_get_next_sibling (row);
+ }
+
+ if (invalidate) {
+@@ -335,28 +338,26 @@ static void
+ choose_non_extras (CcInputChooser *chooser)
+ {
+ CcInputChooserPrivate *priv;
+- GtkWidget *row;
+ guint count = 0;
++ gsize i;
+
+ priv = cc_input_chooser_get_instance_private (chooser);
+- row = gtk_widget_get_first_child (priv->input_list);
+- while (row) {
++
++ for (i = 0; i < priv->input_widget_boxes->len; i++) {
+ InputWidget *widget;
+ GtkWidget *child;
+
+ if (++count > MIN_ROWS)
+ break;
+
+- child = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (row));
++ child = g_ptr_array_index (priv->input_widget_boxes, i);
+ widget = get_input_widget (child);
+- if (widget == NULL)
+- break;
++ g_assert (widget != NULL);
++ g_assert (widget->box == child);
+
+ g_debug ("Picking %s (%s:%s) as non-extra",
+ widget->name, widget->type, widget->id);
+ widget->is_extra = FALSE;
+-
+- row = gtk_widget_get_next_sibling (row);
+ }
+
+ /* Changing is_extra above affects the ordering and the visibility
+@@ -391,6 +392,7 @@ add_rows_to_list (CcInputChooser *chooser,
+ g_hash_table_add (priv->inputs, key);
+
+ widget = input_widget_new (chooser, type, id, TRUE);
++ g_ptr_array_add (priv->input_widget_boxes, g_object_ref_sink (widget));
+ gtk_list_box_append (GTK_LIST_BOX (priv->input_list), widget);
+ }
+ }
+@@ -588,21 +590,21 @@ update_ibus_active_sources (CcInputChooser *chooser)
+ {
+ CcInputChooserPrivate *priv;
+ IBusEngineDesc *engine_desc;
+- GtkWidget *child;
+ const gchar *type;
+ const gchar *id;
+ gchar *name;
++ gsize i;
+
+ priv = cc_input_chooser_get_instance_private (chooser);
+- child = gtk_widget_get_first_child (priv->input_list);
+- while (child) {
+- InputWidget *row;
+
+- row = get_input_widget (child);
+- child = gtk_widget_get_next_sibling (child);
++ for (i = 0; i < priv->input_widget_boxes->len; i++) {
++ GtkWidget *child;
++ InputWidget *row;
+
+- if (row == NULL)
+- continue;
++ child = g_ptr_array_index (priv->input_widget_boxes, i);
++ row = get_input_widget (child);
++ g_assert (row != NULL);
++ g_assert (row->box == child);
+
+ type = row->type;
+ id = row->id;
+@@ -774,6 +776,7 @@ cc_input_chooser_finalize (GObject *object)
+
+ g_clear_object (&priv->xkb_info);
+ g_hash_table_unref (priv->inputs);
++ g_clear_pointer (&priv->input_widget_boxes, g_ptr_array_unref);
+ #ifdef HAVE_IBUS
+ g_clear_object (&priv->ibus);
+ if (priv->ibus_cancellable)
+@@ -844,7 +847,10 @@ cc_input_chooser_class_init (CcInputChooserClass *klass)
+ static void
+ cc_input_chooser_init (CcInputChooser *chooser)
+ {
++ CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
++
+ gtk_widget_init_template (GTK_WIDGET (chooser));
++ priv->input_widget_boxes = g_ptr_array_new_with_free_func (g_object_unref);
+ }
+
+ void