From 65965bed16df9745145fa8878f68db02d539aab0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 20 Mar 2019 15:37:15 +0000 Subject: [PATCH] Changes after review - Rename GtkLegacyLayout to GtkCustomLayout - Use for() to iterate over children in GtkBinLayout - Whitespace fixes for code imported from GtkBox - Store the GtkLayoutChild instances inside LayoutManager - Simplify the GtkLayoutManager API by dropping unnecessary arguments - Fix the ownership model of GtkLayoutManager --- gtk/gtk.h | 1 + gtk/gtkbinlayout.c | 49 +++++++------ gtk/gtkbinlayout.h | 14 +++- gtk/gtkboxlayout.c | 72 +++++++++---------- gtk/gtkcustomlayout.c | 130 +++++++++++++++++++++++++++++++++++ gtk/gtkcustomlayout.h | 77 +++++++++++++++++++++ gtk/gtklayoutmanager.c | 71 ++++++++++++------- gtk/gtklayoutmanager.h | 13 ++-- gtk/gtklegacylayout.c | 129 ---------------------------------- gtk/gtklegacylayoutprivate.h | 33 --------- gtk/gtksizerequest.c | 2 +- gtk/gtkswitch.c | 5 +- gtk/gtkwidget.c | 20 +++--- gtk/meson.build | 3 +- 14 files changed, 355 insertions(+), 264 deletions(-) create mode 100644 gtk/gtkcustomlayout.c create mode 100644 gtk/gtkcustomlayout.h delete mode 100644 gtk/gtklegacylayout.c delete mode 100644 gtk/gtklegacylayoutprivate.h diff --git a/gtk/gtk.h b/gtk/gtk.h index 27a29e951f..6d1ca27b5f 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -82,6 +82,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkbinlayout.c b/gtk/gtkbinlayout.c index d5cc211e7e..cbc3510892 100644 --- a/gtk/gtkbinlayout.c +++ b/gtk/gtkbinlayout.c @@ -1,8 +1,18 @@ /* gtkbinlayout.c: Layout manager for bin-like widgets - * * Copyright 2019 GNOME Foundation * - * SPDX-License-Identifier: LGPL 2.1+ + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . */ /** @@ -43,23 +53,29 @@ gtk_bin_layout_measure (GtkLayoutManager *layout_manager, { GtkWidget *child; - child = _gtk_widget_get_first_child (widget); - while (child != NULL) + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) { - GtkWidget *next = _gtk_widget_get_next_sibling (child); - if (gtk_widget_get_visible (child)) { int child_min = 0; int child_nat = 0; + int child_min_baseline = -1; + int child_nat_baseline = -1; - gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL); + gtk_widget_measure (child, orientation, for_size, + &child_min, &child_nat, + &child_min_baseline, &child_nat_baseline); *minimum = MAX (*minimum, child_min); *natural = MAX (*natural, child_nat); - } - child = next; + if (child_min_baseline > -1) + *minimum_baseline = MAX (*minimum_baseline, child_min_baseline); + if (child_nat_baseline > -1) + *natural_baseline = MAX (*natural_baseline, child_nat_baseline); + } } } @@ -72,19 +88,12 @@ gtk_bin_layout_allocate (GtkLayoutManager *layout_manager, { GtkWidget *child; - child = _gtk_widget_get_first_child (widget); - while (child != NULL) + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) { - GtkWidget *next = _gtk_widget_get_next_sibling (child); - if (child && gtk_widget_get_visible (child)) - gtk_widget_size_allocate (child, - &(GtkAllocation) { - 0, 0, - width, height - }, baseline); - - child = next; + gtk_widget_allocate (child, width, height, baseline, NULL); } } static void diff --git a/gtk/gtkbinlayout.h b/gtk/gtkbinlayout.h index b19581f2eb..400bafc733 100644 --- a/gtk/gtkbinlayout.h +++ b/gtk/gtkbinlayout.h @@ -1,8 +1,18 @@ /* gtkbinlayout.h: Layout manager for bin-like widgets - * * Copyright 2019 GNOME Foundation * - * SPDX-License-Identifier: LGPL 2.1+ + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . */ #pragma once diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c index 99167163b3..0b88e39fcf 100644 --- a/gtk/gtkboxlayout.c +++ b/gtk/gtkboxlayout.c @@ -9,7 +9,7 @@ * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public @@ -303,7 +303,7 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self, child = _gtk_widget_get_next_sibling (child)) { if (_gtk_widget_get_visible (child)) - { + { gtk_widget_measure (child, self->orientation, -1, @@ -311,8 +311,8 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self, NULL, NULL); children_minimum_size += sizes[i].minimum_size; - i += 1; - } + i += 1; + } } if (self->homogeneous) @@ -335,10 +335,10 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self, * and is available for expanding children. */ if (nexpand_children > 0) - { + { size_given_to_child = extra_space / nexpand_children; n_extra_widgets = extra_space % nexpand_children; - } + } else { size_given_to_child = 0; @@ -410,22 +410,22 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self, computed_minimum = MAX (computed_minimum, computed_minimum_below + computed_minimum_above); computed_natural = MAX (computed_natural, computed_natural_below + computed_natural_above); switch (self->baseline_position) - { - case GTK_BASELINE_POSITION_TOP: - computed_minimum_baseline = computed_minimum_above; - computed_natural_baseline = computed_natural_above; - break; - case GTK_BASELINE_POSITION_CENTER: - computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0); - computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0); - break; - case GTK_BASELINE_POSITION_BOTTOM: - computed_minimum_baseline = computed_minimum - computed_minimum_below; - computed_natural_baseline = computed_natural - computed_natural_below; - break; + { + case GTK_BASELINE_POSITION_TOP: + computed_minimum_baseline = computed_minimum_above; + computed_natural_baseline = computed_natural_above; + break; + case GTK_BASELINE_POSITION_CENTER: + computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0); + computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0); + break; + case GTK_BASELINE_POSITION_BOTTOM: + computed_minimum_baseline = computed_minimum - computed_minimum_below; + computed_natural_baseline = computed_natural - computed_natural_below; + break; default: break; - } + } } if (minimum != NULL) @@ -515,7 +515,7 @@ gtk_box_layout_allocate (GtkLayoutManager *layout_manager, child = _gtk_widget_get_next_sibling (child)) { if (!_gtk_widget_get_visible (child)) - continue; + continue; gtk_widget_measure (child, self->orientation, @@ -550,10 +550,10 @@ gtk_box_layout_allocate (GtkLayoutManager *layout_manager, * and is available for expanding children. */ if (nexpand_children > 0) - { + { size_given_to_child = extra_space / nexpand_children; n_extra_widgets = extra_space % nexpand_children; - } + } else { size_given_to_child = 0; @@ -634,22 +634,22 @@ gtk_box_layout_allocate (GtkLayoutManager *layout_manager, if (baseline == -1 && have_baseline) { /* TODO: This is purely based on the minimum baseline, when things fit we should - use the natural one? */ + use the natural one? */ switch (self->baseline_position) - { - case GTK_BASELINE_POSITION_TOP: - baseline = minimum_above; - break; - case GTK_BASELINE_POSITION_CENTER: - baseline = minimum_above + (height - (minimum_above + minimum_below)) / 2; - break; - case GTK_BASELINE_POSITION_BOTTOM: - baseline = height - minimum_below; - break; + { + case GTK_BASELINE_POSITION_TOP: + baseline = minimum_above; + break; + case GTK_BASELINE_POSITION_CENTER: + baseline = minimum_above + (height - (minimum_above + minimum_below)) / 2; + break; + case GTK_BASELINE_POSITION_BOTTOM: + baseline = height - minimum_below; + break; default: break; - } + } } /* Allocate child positions. */ @@ -846,7 +846,7 @@ gtk_box_layout_get_spacing (GtkBoxLayout *box_layout) */ void gtk_box_layout_set_baseline_position (GtkBoxLayout *box_layout, - GtkBaselinePosition position) + GtkBaselinePosition position) { g_return_if_fail (GTK_IS_BOX_LAYOUT (box_layout)); diff --git a/gtk/gtkcustomlayout.c b/gtk/gtkcustomlayout.c new file mode 100644 index 0000000000..a1bfe95fff --- /dev/null +++ b/gtk/gtkcustomlayout.c @@ -0,0 +1,130 @@ +/** + * SECTION:gtkcustomlayout + * @Title: GtkCustomLayout + * @Short_description: A convenience layout manager + * + * #GtkCustomLayout is a convenience type meant to be used as a transition + * mechanism between #GtkContainers implementing a layout policy, and + * #GtkLayoutManager classes. + * + * A #GtkCustomLayout uses closures matching to the old #GtkWidget virtual + * functions for size negotiation, as a convenience API to ease the porting + * towards the corresponding #GtkLayoutManager virtual functions. + */ + +#include "config.h" + +#include "gtkcustomlayout.h" + +struct _GtkCustomLayout +{ + GtkLayoutManager parent_instance; + + GtkCustomRequestModeFunc request_mode_func; + GtkCustomMeasureFunc measure_func; + GtkCustomAllocateFunc allocate_func; +}; + +G_DEFINE_TYPE (GtkCustomLayout, gtk_custom_layout, GTK_TYPE_LAYOUT_MANAGER) + +static GtkSizeRequestMode +gtk_custom_layout_get_request_mode (GtkLayoutManager *manager, + GtkWidget *widget) +{ + GtkCustomLayout *self = GTK_CUSTOM_LAYOUT (manager); + + if (self->request_mode_func != NULL) + return self->request_mode_func (widget); + + return GTK_SIZE_REQUEST_CONSTANT_SIZE; +} + +static void +gtk_custom_layout_measure (GtkLayoutManager *manager, + GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkCustomLayout *self = GTK_CUSTOM_LAYOUT (manager); + int min = 0, nat = 0; + int min_baseline = -1, nat_baseline = -1; + + self->measure_func (widget, orientation, for_size, + &min, &nat, + &min_baseline, &nat_baseline); + + if (minimum != NULL) + *minimum = min; + if (natural != NULL) + *natural = nat; + + if (minimum_baseline != NULL) + *minimum_baseline = min_baseline; + if (natural_baseline != NULL) + *natural_baseline = nat_baseline; +} + +static void +gtk_custom_layout_allocate (GtkLayoutManager *manager, + GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkCustomLayout *self = GTK_CUSTOM_LAYOUT (manager); + + self->allocate_func (widget, width, height, baseline); +} + +static void +gtk_custom_layout_class_init (GtkCustomLayoutClass *klass) +{ + GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (klass); + + layout_class->get_request_mode = gtk_custom_layout_get_request_mode; + layout_class->measure = gtk_custom_layout_measure; + layout_class->allocate = gtk_custom_layout_allocate; +} + +static void +gtk_custom_layout_init (GtkCustomLayout *self) +{ +} + +/** + * gtk_custom_layout_new: + * @request_mode: (nullable): a function to retrieve + * the #GtkSizeRequestMode of the widget using the layout; the + * default request mode is %GTK_SIZE_REQUEST_CONSTANT_SIZE + * @measure: a function to measure the widget using the layout manager + * @allocate: a function to allocate the children of the widget using + * the layout manager + * + * Creates a new legacy layout manager. + * + * Legacy layout managers map to the old #GtkWidget size negotiation + * virtual functions, and are meant to be used during the transition + * from layout containers to layout manager delegates. + * + * Returns: (transfer full): the newly created #GtkCustomLayout + */ +GtkLayoutManager * +gtk_custom_layout_new (GtkCustomRequestModeFunc request_mode, + GtkCustomMeasureFunc measure, + GtkCustomAllocateFunc allocate) +{ + GtkCustomLayout *self = g_object_new (GTK_TYPE_CUSTOM_LAYOUT, NULL); + + g_return_val_if_fail (measure != NULL, NULL); + g_return_val_if_fail (allocate != NULL, NULL); + + self->request_mode_func = request_mode; + self->measure_func = measure; + self->allocate_func = allocate; + + return GTK_LAYOUT_MANAGER (self); +} diff --git a/gtk/gtkcustomlayout.h b/gtk/gtkcustomlayout.h new file mode 100644 index 0000000000..21beb04853 --- /dev/null +++ b/gtk/gtkcustomlayout.h @@ -0,0 +1,77 @@ +/* gtkcustomlayout.h: Simple layout manager + * Copyright 2019 GNOME Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ +#pragma once + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CUSTOM_LAYOUT (gtk_custom_layout_get_type ()) + +/** + * GtkCustomRequestModeFunc: + * @widget: the widget to be queried + * + * Queries a widget for its preferred size request mode. + * + * Returns: the size request mode + */ +typedef GtkSizeRequestMode (* GtkCustomRequestModeFunc) (GtkWidget *widget); + +/** + * GtkCustomMeasureFunc: + * @widget: the widget to be measured + * @orientation: the direction to be measured + * @for_size: the size to be measured for + * @minimum: (out): the measured minimum size of the widget + * @natural: (out): the measured natural size of the widget + * @minimum_baseline: (out): the measured minimum baseline of the widget + * @natural_baseline: (out): the measured natural baseline of the widget + * + * A function to be used by #GtkCustomLayout to measure a widget. + */ +typedef void (* GtkCustomMeasureFunc) (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline); + +/** + * GtkCustomAllocateFunc: + * @widget: the widget to allocate + * @width: the new width of the widget + * @height: the new height of the widget + * @baseline: the new baseline of the widget, or -1 + * + * A function to be used by #GtkCustomLayout to allocate a widget. + */ +typedef void (* GtkCustomAllocateFunc) (GtkWidget *widget, + int width, + int height, + int baseline); + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkCustomLayout, gtk_custom_layout, GTK, CUSTOM_LAYOUT, GtkLayoutManager) + +GDK_AVAILABLE_IN_ALL +GtkLayoutManager * gtk_custom_layout_new (GtkCustomRequestModeFunc request_mode, + GtkCustomMeasureFunc measure, + GtkCustomAllocateFunc allocate); + +G_END_DECLS diff --git a/gtk/gtklayoutmanager.c b/gtk/gtklayoutmanager.c index 02abe0d5c7..9ac3d986b7 100644 --- a/gtk/gtklayoutmanager.c +++ b/gtk/gtklayoutmanager.c @@ -26,9 +26,8 @@ * and the allocation of a container widget. * * You typically subclass #GtkLayoutManager if you want to implement a - * layout policy for the children of a widget, without necessarily - * implementing the @GtkWidgetClass.measure() and @GtkWidgetClass.size_allocate() - * virtual functions directly. + * layout policy for the children of a widget, or if you want to determine + * the size of a widget depending on its contents. * * Each #GtkWidget can only have a #GtkLayoutManager instance associated to it * at any given time; it is possible, though, to replace the layout manager @@ -54,6 +53,9 @@ typedef struct { GtkWidget *widget; + + /* HashTable */ + GHashTable *layout_children; } GtkLayoutManagerPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkLayoutManager, gtk_layout_manager, G_TYPE_OBJECT) @@ -200,7 +202,7 @@ gtk_layout_manager_measure (GtkLayoutManager *manager, * @widget: the #GtkWidget using @manager * @width: the new width of the @widget * @height: the new height of the @widget - * @baseline: the baseline position of the @widget + * @baseline: the baseline position of the @widget, or -1 * * This function assigns the given @width, @height, and @baseline to * a @widget, and computes the position and sizes of the children of @@ -217,6 +219,7 @@ gtk_layout_manager_allocate (GtkLayoutManager *manager, g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (baseline >= -1); klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager); @@ -226,24 +229,22 @@ gtk_layout_manager_allocate (GtkLayoutManager *manager, /** * gtk_layout_manager_get_request_mode: * @manager: a #GtkLayoutManager - * @widget: the #GtkWidget using @manager * * Retrieves the request mode of @manager. * * Returns: a #GtkSizeRequestMode */ GtkSizeRequestMode -gtk_layout_manager_get_request_mode (GtkLayoutManager *manager, - GtkWidget *widget) +gtk_layout_manager_get_request_mode (GtkLayoutManager *manager) { + GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager); GtkLayoutManagerClass *klass; g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), GTK_SIZE_REQUEST_CONSTANT_SIZE); - g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_SIZE_REQUEST_CONSTANT_SIZE); klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager); - return klass->get_request_mode (manager, widget); + return klass->get_request_mode (manager, priv->widget); } /** @@ -284,32 +285,51 @@ gtk_layout_manager_layout_changed (GtkLayoutManager *manager) gtk_widget_queue_resize (priv->widget); } +static void +remove_layout_child (GtkWidget *widget, + GtkWidget *old_parent, + GtkLayoutManager *self) +{ + GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (self); + + if (priv->layout_children != NULL) + { + g_hash_table_remove (priv->layout_children, widget); + if (g_hash_table_size (priv->layout_children) == 0) + g_clear_pointer (&priv->layout_children, g_hash_table_unref); + } + + g_signal_handlers_disconnect_by_func (widget, remove_layout_child, self); +} + /** * gtk_layout_manager_get_layout_child: * @manager: a #GtkLayoutManager - * @widget: a #GtkWidget + * @child: a #GtkWidget * * Retrieves a #GtkLayoutChild instance for the #GtkLayoutManager, creating - * one if necessary + * one if necessary. + * + * The @child widget must be a child of the widget using @manager. * * The #GtkLayoutChild instance is owned by the #GtkLayoutManager, and is - * guaranteed to exist as long as @widget is a child of the #GtkWidget using + * guaranteed to exist as long as @child is a child of the #GtkWidget using * the given #GtkLayoutManager. * * Returns: (transfer none): a #GtkLayoutChild */ GtkLayoutChild * gtk_layout_manager_get_layout_child (GtkLayoutManager *manager, - GtkWidget *widget) + GtkWidget *child) { GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager); GtkLayoutChild *res; GtkWidget *parent; g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), NULL); - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + g_return_val_if_fail (GTK_IS_WIDGET (child), NULL); - parent = gtk_widget_get_parent (widget); + parent = gtk_widget_get_parent (child); g_return_val_if_fail (parent != NULL, NULL); if (priv->widget != parent) @@ -317,7 +337,7 @@ gtk_layout_manager_get_layout_child (GtkLayoutManager *manager, g_critical ("The parent %s %p of the widget %s %p does not " "use the given layout manager of type %s %p", gtk_widget_get_name (parent), parent, - gtk_widget_get_name (widget), widget, + gtk_widget_get_name (child), child, G_OBJECT_TYPE_NAME (manager), manager); return NULL; } @@ -330,10 +350,14 @@ gtk_layout_manager_get_layout_child (GtkLayoutManager *manager, return NULL; } - /* We store the LayoutChild into the Widget, so that the LayoutChild - * instance goes away once the Widget goes away - */ - res = g_object_get_qdata (G_OBJECT (widget), quark_layout_child); + if (priv->layout_children == NULL) + { + priv->layout_children = g_hash_table_new_full (NULL, NULL, + NULL, + (GDestroyNotify) g_object_unref); + } + + res = g_hash_table_lookup (priv->layout_children, child); if (res != NULL) { /* If the LayoutChild instance is stale, and refers to another @@ -345,13 +369,12 @@ gtk_layout_manager_get_layout_child (GtkLayoutManager *manager, return res; } - res = GTK_LAYOUT_MANAGER_GET_CLASS (manager)->create_layout_child (manager, widget); + res = GTK_LAYOUT_MANAGER_GET_CLASS (manager)->create_layout_child (manager, parent, child); g_assert (res != NULL); g_assert (g_type_is_a (G_OBJECT_TYPE (res), GTK_TYPE_LAYOUT_CHILD)); - g_object_set_qdata_full (G_OBJECT (widget), quark_layout_child, - res, - g_object_unref); + g_hash_table_insert (priv->layout_children, child, res); + g_signal_connect (child, "parent-set", G_CALLBACK (remove_layout_child), manager); return res; } diff --git a/gtk/gtklayoutmanager.h b/gtk/gtklayoutmanager.h index 02f2173a36..53f4931c69 100644 --- a/gtk/gtklayoutmanager.h +++ b/gtk/gtklayoutmanager.h @@ -1,5 +1,5 @@ /* gtklayoutmanager.h: Layout manager base class - * Copyright 2018 The GNOME Foundation + * Copyright 2019 The GNOME Foundation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,6 +18,7 @@ */ #pragma once +#include #include #include #include @@ -38,6 +39,8 @@ G_DECLARE_DERIVABLE_TYPE (GtkLayoutManager, gtk_layout_manager, GTK, LAYOUT_MANA * sizes of the widget using the layout manager for a given orientation * @allocate: a virtual function, used to allocate the size of the widget * using the layout manager + * @create_layout_child: a virtual function, used to create a #GtkLayoutChild + * meta object for the layout properties * * The `GtkLayoutManagerClass` structure contains only private data, and * should only be accessed through the provided API, or when subclassing @@ -68,7 +71,8 @@ struct _GtkLayoutManagerClass int baseline); GtkLayoutChild * (* create_layout_child) (GtkLayoutManager *manager, - GtkWidget *widget); + GtkWidget *widget, + GtkWidget *for_child); /*< private >*/ gpointer _padding[16]; @@ -90,8 +94,7 @@ void gtk_layout_manager_allocate (GtkLayoutManage int height, int baseline); GDK_AVAILABLE_IN_ALL -GtkSizeRequestMode gtk_layout_manager_get_request_mode (GtkLayoutManager *manager, - GtkWidget *widget); +GtkSizeRequestMode gtk_layout_manager_get_request_mode (GtkLayoutManager *manager); GDK_AVAILABLE_IN_ALL GtkWidget * gtk_layout_manager_get_widget (GtkLayoutManager *manager); @@ -101,6 +104,6 @@ void gtk_layout_manager_layout_changed (GtkLayoutManage GDK_AVAILABLE_IN_ALL GtkLayoutChild * gtk_layout_manager_get_layout_child (GtkLayoutManager *manager, - GtkWidget *widget); + GtkWidget *child); G_END_DECLS diff --git a/gtk/gtklegacylayout.c b/gtk/gtklegacylayout.c deleted file mode 100644 index 1e08a65cbc..0000000000 --- a/gtk/gtklegacylayout.c +++ /dev/null @@ -1,129 +0,0 @@ -/*< private > - * SECTION:gtklegacylayout - * @Title: GtkLegacyLayout - * @Short_description: A legacy layout manager - * - * #GtkLegacyLayout is a convenience type meant to be used as a transition - * mechanism between #GtkContainers implementing a layout policy, and - * #GtkLayoutManager classes. - * - * A #GtkLegacyLayout uses closures matching to the old #GtkWidget virtual - * functions for size negotiation, to ease the porting towards the - * corresponding #GtkLayoutManager virtual functions. - */ - -#include "config.h" - -#include "gtklegacylayoutprivate.h" - -struct _GtkLegacyLayout -{ - GtkLayoutManager parent_instance; - - GtkLegacyRequestModeFunc request_mode_func; - GtkLegacyMeasureFunc measure_func; - GtkLegacyAllocateFunc allocate_func; -}; - -G_DEFINE_TYPE (GtkLegacyLayout, gtk_legacy_layout, GTK_TYPE_LAYOUT_MANAGER) - -static GtkSizeRequestMode -gtk_legacy_layout_get_request_mode (GtkLayoutManager *manager, - GtkWidget *widget) -{ - GtkLegacyLayout *self = GTK_LEGACY_LAYOUT (manager); - - if (self->request_mode_func != NULL) - return self->request_mode_func (widget); - - return GTK_SIZE_REQUEST_CONSTANT_SIZE; -} - -static void -gtk_legacy_layout_measure (GtkLayoutManager *manager, - GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum_p, - int *natural_p, - int *minimum_baseline_p, - int *natural_baseline_p) -{ - GtkLegacyLayout *self = GTK_LEGACY_LAYOUT (manager); - int minimum = 0, natural = 0; - int minimum_baseline = -1, natural_baseline = -1; - - if (self->measure_func != NULL) - self->measure_func (widget, orientation, for_size, - &minimum, &natural, - &minimum_baseline, &natural_baseline); - - if (minimum_p != NULL) - *minimum_p = minimum; - if (natural_p != NULL) - *natural_p = natural; - - if (minimum_baseline_p != NULL) - *minimum_baseline_p = minimum_baseline; - if (natural_baseline_p != NULL) - *natural_baseline_p = natural_baseline; -} - -static void -gtk_legacy_layout_allocate (GtkLayoutManager *manager, - GtkWidget *widget, - int width, - int height, - int baseline) -{ - GtkLegacyLayout *self = GTK_LEGACY_LAYOUT (manager); - - if (self->allocate_func != NULL) - self->allocate_func (widget, width, height, baseline); -} - -static void -gtk_legacy_layout_class_init (GtkLegacyLayoutClass *klass) -{ - GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (klass); - - layout_class->get_request_mode = gtk_legacy_layout_get_request_mode; - layout_class->measure = gtk_legacy_layout_measure; - layout_class->allocate = gtk_legacy_layout_allocate; -} - -static void -gtk_legacy_layout_init (GtkLegacyLayout *self) -{ -} - -/*< private > - * gtk_legacy_layout_new: - * @request_mode: (nullable): a function to retrieve - * the #GtkSizeRequestMode of the widget using the layout - * @measure: (nullable): a fucntion to measure the widget - * using the layout - * @allocate: (nullable): a function to allocate the children - * of the widget using the layout - * - * Creates a new legacy layout manager. - * - * Legacy layout managers map to the old #GtkWidget size negotiation - * virtual functions, and are meant to be used during the transition - * from layout containers to layout manager delegates. - * - * Returns: (transfer full): the newly created #GtkLegacyLayout - */ -GtkLayoutManager * -gtk_legacy_layout_new (GtkLegacyRequestModeFunc request_mode, - GtkLegacyMeasureFunc measure, - GtkLegacyAllocateFunc allocate) -{ - GtkLegacyLayout *self = g_object_new (GTK_TYPE_LEGACY_LAYOUT, NULL); - - self->request_mode_func = request_mode; - self->measure_func = measure; - self->allocate_func = allocate; - - return GTK_LAYOUT_MANAGER (self); -} diff --git a/gtk/gtklegacylayoutprivate.h b/gtk/gtklegacylayoutprivate.h deleted file mode 100644 index 47fe5d6998..0000000000 --- a/gtk/gtklegacylayoutprivate.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_LEGACY_LAYOUT (gtk_legacy_layout_get_type ()) - -typedef GtkSizeRequestMode (* GtkLegacyRequestModeFunc) (GtkWidget *widget); - -typedef void (* GtkLegacyMeasureFunc) (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline); - -typedef void (* GtkLegacyAllocateFunc) (GtkWidget *widget, - int width, - int height, - int baseline); - -GDK_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (GtkLegacyLayout, gtk_legacy_layout, GTK, LEGACY_LAYOUT, GtkLayoutManager) - -GDK_AVAILABLE_IN_ALL -GtkLayoutManager * -gtk_legacy_layout_new (GtkLegacyRequestModeFunc request_mode, - GtkLegacyMeasureFunc measure, - GtkLegacyAllocateFunc allocate); - -G_END_DECLS diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c index d9b24ad8e8..5330a59a1f 100644 --- a/gtk/gtksizerequest.c +++ b/gtk/gtksizerequest.c @@ -565,7 +565,7 @@ gtk_widget_get_request_mode (GtkWidget *widget) GtkLayoutManager *layout_manager = gtk_widget_get_layout_manager (widget); if (layout_manager != NULL) - cache->request_mode = gtk_layout_manager_get_request_mode (layout_manager, widget); + cache->request_mode = gtk_layout_manager_get_request_mode (layout_manager); else cache->request_mode = GTK_WIDGET_GET_CLASS (widget)->get_request_mode (widget); diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c index 420927f13e..56a077abd5 100644 --- a/gtk/gtkswitch.c +++ b/gtk/gtkswitch.c @@ -61,7 +61,7 @@ #include "gtkgizmoprivate.h" #include "gtkintl.h" #include "gtkimage.h" -#include "gtklegacylayoutprivate.h" +#include "gtkcustomlayout.h" #include "gtkmarshalers.h" #include "gtkprivate.h" #include "gtkprogresstrackerprivate.h" @@ -641,11 +641,10 @@ gtk_switch_init (GtkSwitch *self) gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture)); priv->pan_gesture = gesture; - layout = gtk_legacy_layout_new (NULL, + layout = gtk_custom_layout_new (NULL, gtk_switch_measure, gtk_switch_allocate); gtk_widget_set_layout_manager (GTK_WIDGET (self), layout); - g_object_unref (layout); priv->on_image = gtk_image_new_from_icon_name ("switch-on-symbolic"); gtk_widget_set_parent (priv->on_image, GTK_WIDGET (self)); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 022cc9b799..9d0dccc665 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -8101,7 +8101,8 @@ gtk_widget_dispose (GObject *object) while (priv->paintables) gtk_widget_paintable_set_widget (priv->paintables->data, NULL); - gtk_widget_set_layout_manager (widget, NULL); + if (priv->layout_manager != NULL) + gtk_layout_manager_set_widget (priv->layout_manager, NULL); g_clear_object (&priv->layout_manager); priv->visible = FALSE; @@ -13653,8 +13654,6 @@ gtk_widget_get_height (GtkWidget *widget) * * Sets the layout manager delegate instance that provides an implementation * for measuring and allocating the children of @widget. - * - * The @widget acquires a reference to the given @layout_manager. */ void gtk_widget_set_layout_manager (GtkWidget *widget, @@ -13666,15 +13665,16 @@ gtk_widget_set_layout_manager (GtkWidget *widget, g_return_if_fail (layout_manager == NULL || GTK_IS_LAYOUT_MANAGER (layout_manager)); g_return_if_fail (layout_manager == NULL || gtk_layout_manager_get_widget (layout_manager) == NULL); - if (g_set_object (&priv->layout_manager, layout_manager)) - { - if (priv->layout_manager != NULL) - gtk_layout_manager_set_widget (priv->layout_manager, widget); + if (priv->layout_manager == layout_manager) + return; - gtk_widget_queue_resize (widget); + priv->layout_manager = layout_manager; + if (priv->layout_manager != NULL) + gtk_layout_manager_set_widget (priv->layout_manager, widget); - g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_LAYOUT_MANAGER]); - } + gtk_widget_queue_resize (widget); + + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_LAYOUT_MANAGER]); } /** diff --git a/gtk/meson.build b/gtk/meson.build index b6a5457876..fd955607b7 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -98,6 +98,7 @@ gtk_private_sources = files([ 'gtkcssunsetvalue.c', 'gtkcssvalue.c', 'gtkcsswidgetnode.c', + 'gtkcustomlayout.c', 'gtkfilechooserembed.c', 'gtkfilechooserentry.c', 'gtkfilechoosererrorstack.c', @@ -114,7 +115,6 @@ gtk_private_sources = files([ 'gtkiconhelper.c', 'gtkkineticscrolling.c', 'gtkkeyhash.c', - 'gtklegacylayout.c', 'gtkmagnifier.c', 'gtkmenusectionbox.c', 'gtkmenutracker.c', @@ -457,6 +457,7 @@ gtk_public_headers = files([ 'gtkcontainer.h', 'gtkcssprovider.h', 'gtkcsssection.h', + 'gtkcustomlayout.h', 'gtkdebug.h', 'gtkdialog.h', 'gtkdnd.h',