diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index ac9ea19fa9..6dc672ce8f 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -7338,6 +7338,10 @@ gtk_constraint_layout_remove_guide gtk_constraint_layout_add_constraints_from_description gtk_constraint_layout_add_constraints_from_descriptionv + +gtk_constraint_layout_observe_constraints +gtk_constraint_layout_observe_guides + GTK_TYPE_CONSTRAINT_LAYOUT gtk_constraint_layout_get_type diff --git a/gtk/gtkconstraintlayout.c b/gtk/gtkconstraintlayout.c index 4623798b5e..f23237e0d8 100644 --- a/gtk/gtkconstraintlayout.c +++ b/gtk/gtkconstraintlayout.c @@ -253,6 +253,9 @@ struct _GtkConstraintLayout /* HashSet */ GHashTable *guides; + + GListStore *constraints_observer; + GListStore *guides_observer; }; G_DEFINE_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK_TYPE_LAYOUT_CHILD) @@ -534,6 +537,19 @@ gtk_constraint_layout_finalize (GObject *gobject) { GtkConstraintLayout *self = GTK_CONSTRAINT_LAYOUT (gobject); + if (self->constraints_observer) + { + g_list_store_remove_all (self->constraints_observer); + g_object_remove_weak_pointer ((GObject *)self->constraints_observer, + (gpointer *)&self->constraints_observer); + } + if (self->guides_observer) + { + g_list_store_remove_all (self->guides_observer); + g_object_remove_weak_pointer ((GObject *)self->guides_observer, + (gpointer *)&self->guides_observer); + } + g_clear_pointer (&self->bound_attributes, g_hash_table_unref); g_clear_pointer (&self->constraints, g_hash_table_unref); g_clear_pointer (&self->guides, g_hash_table_unref); @@ -1709,10 +1725,32 @@ gtk_constraint_layout_add_constraint (GtkConstraintLayout *layout, layout_add_constraint (layout, constraint); g_hash_table_add (layout->constraints, constraint); + if (layout->constraints_observer) + g_list_store_append (layout->constraints_observer, constraint); gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); } +static void +list_store_remove_item (GListStore *store, + gpointer item) +{ + int n_items; + int i; + + n_items = g_list_model_get_n_items (G_LIST_MODEL (store)); + for (i = 0; i < n_items; i++) + { + gpointer *model_item = g_list_model_get_item (G_LIST_MODEL (store), i); + g_object_unref (model_item); + if (item == model_item) + { + g_list_store_remove (store, i); + break; + } + } +} + /** * gtk_constraint_layout_remove_constraint: * @layout: a #GtkConstraintLayout @@ -1731,6 +1769,8 @@ gtk_constraint_layout_remove_constraint (GtkConstraintLayout *layout, gtk_constraint_detach (constraint); g_hash_table_remove (layout->constraints, constraint); + if (layout->constraints_observer) + list_store_remove_item (layout->constraints_observer, constraint); gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); } @@ -1757,6 +1797,8 @@ gtk_constraint_layout_remove_all_constraints (GtkConstraintLayout *layout) gtk_constraint_detach (constraint); g_hash_table_iter_remove (&iter); } + if (layout->constraints_observer) + g_list_store_remove_all (layout->constraints_observer); gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); } @@ -1783,6 +1825,8 @@ gtk_constraint_layout_add_guide (GtkConstraintLayout *layout, gtk_constraint_guide_set_layout (guide, layout); g_hash_table_add (layout->guides, guide); + if (layout->guides_observer) + g_list_store_append (layout->guides_observer, guide); gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); } @@ -1807,6 +1851,8 @@ gtk_constraint_layout_remove_guide (GtkConstraintLayout *layout, gtk_constraint_guide_set_layout (guide, NULL); g_hash_table_remove (layout->guides, guide); + if (layout->guides_observer) + list_store_remove_item (layout->guides_observer, guide); gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); } @@ -2026,6 +2072,8 @@ gtk_constraint_layout_add_constraints_from_descriptionv (GtkConstraintLayout *la layout_add_constraint (layout, constraint); g_hash_table_add (layout->constraints, constraint); + if (layout->constraints_observer) + g_list_store_append (layout->constraints_observer, constraint); res = g_list_prepend (res, constraint); } @@ -2116,3 +2164,83 @@ gtk_constraint_layout_add_constraints_from_description (GtkConstraintLayout *lay return res; } + +/** + * gtk_constraint_layout_observe_constraints: + * @layout: a #GtkConstraintLayout + * + * Returns a #GListModel to track the constraints that are + * part of @layout. + * + * Calling this function will enable extra internal bookkeeping + * to track constraints and emit signals on the returned listmodel. + * It may slow down operations a lot. + * + * Applications should try hard to avoid calling this function + * because of the slowdowns. + * + * Returns: (transfer full): a #GListModel tracking @layout's + * constraints + */ +GListModel * +gtk_constraint_layout_observe_constraints (GtkConstraintLayout *layout) +{ + GHashTableIter iter; + gpointer key; + + if (layout->constraints_observer) + return g_object_ref (G_LIST_MODEL (layout->constraints_observer)); + + layout->constraints_observer = g_list_store_new (GTK_TYPE_CONSTRAINT); + g_object_add_weak_pointer ((GObject *)layout->constraints_observer, + (gpointer *)&layout->constraints_observer); + + g_hash_table_iter_init (&iter, layout->constraints); + while (g_hash_table_iter_next (&iter, &key, NULL)) + { + GtkConstraint *constraint = key; + g_list_store_append (layout->constraints_observer, constraint); + } + + return G_LIST_MODEL (layout->constraints_observer); +} + +/** + * gtk_constraint_layout_observe_guides: + * @layout: a #GtkConstraintLayout + * + * Returns a #GListModel to track the guides that are + * part of @layout. + * + * Calling this function will enable extra internal bookkeeping + * to track guides and emit signals on the returned listmodel. + * It may slow down operations a lot. + * + * Applications should try hard to avoid calling this function + * because of the slowdowns. + * + * Returns: (transfer full): a #GListModel tracking @layout's + * guides + */ +GListModel * +gtk_constraint_layout_observe_guides (GtkConstraintLayout *layout) +{ + GHashTableIter iter; + gpointer key; + + if (layout->guides_observer) + return g_object_ref (G_LIST_MODEL (layout->guides_observer)); + + layout->guides_observer = g_list_store_new (GTK_TYPE_CONSTRAINT_GUIDE); + g_object_add_weak_pointer ((GObject *)layout->guides_observer, + (gpointer *)&layout->guides_observer); + + g_hash_table_iter_init (&iter, layout->guides); + while (g_hash_table_iter_next (&iter, &key, NULL)) + { + GtkConstraintGuide *guide = key; + g_list_store_append (layout->guides_observer, guide); + } + + return G_LIST_MODEL (layout->guides_observer); +} diff --git a/gtk/gtkconstraintlayout.h b/gtk/gtkconstraintlayout.h index 90d5e84926..fc7c6a468b 100644 --- a/gtk/gtkconstraintlayout.h +++ b/gtk/gtkconstraintlayout.h @@ -85,4 +85,9 @@ GList * gtk_constraint_layout_add_constraints_from_descriptionv GHashTable *views, GError **error); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_constraint_layout_observe_constraints (GtkConstraintLayout *layout); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_constraint_layout_observe_guides (GtkConstraintLayout *layout); + G_END_DECLS