From 519967cc6939ffa21f39fed9884f6de1e3341a5c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Wed, 11 Sep 2019 18:15:30 +0200 Subject: [PATCH] headerbar: Use a center layout Get rid of the custom title centering etc. and use a GtkCenterLayout. Use a box on the start/end to manage the child widgets. --- gtk/gtkheaderbar.c | 900 +++++++-------------------------------------- 1 file changed, 131 insertions(+), 769 deletions(-) diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c index d8ddc7d155..22c9c50bc8 100644 --- a/gtk/gtkheaderbar.c +++ b/gtk/gtkheaderbar.c @@ -24,6 +24,7 @@ #include "gtkbox.h" #include "gtkbutton.h" #include "gtkbuildable.h" +#include "gtkcenterlayout.h" #include "gtkcontainerprivate.h" #include "gtkcssnodeprivate.h" #include "gtkimage.h" @@ -84,6 +85,9 @@ struct _GtkHeaderBarClass struct _GtkHeaderBarPrivate { + GtkWidget *start_box; + GtkWidget *end_box; + gchar *title; gchar *subtitle; GtkWidget *title_label; @@ -95,8 +99,6 @@ struct _GtkHeaderBarPrivate gint spacing; gboolean has_subtitle; - GList *children; - gboolean show_title_buttons; gchar *decoration_layout; gboolean decoration_layout_set; @@ -115,13 +117,6 @@ struct _GtkHeaderBarPrivate guint shows_app_menu : 1; }; -typedef struct _Child Child; -struct _Child -{ - GtkWidget *widget; - GtkPackType pack_type; -}; - enum { PROP_0, PROP_TITLE, @@ -255,19 +250,23 @@ _gtk_header_bar_update_separator_visibility (GtkHeaderBar *bar) gboolean have_visible_at_start = FALSE; gboolean have_visible_at_end = FALSE; GList *l; - - for (l = priv->children; l != NULL; l = l->next) + GList *children; + + children = gtk_container_get_children (GTK_CONTAINER (priv->start_box)); + for (l = children; l; l = l->next) { - Child *child = l->data; + if (l->data != priv->titlebar_start_box && gtk_widget_get_visible (l->data)) + have_visible_at_start = TRUE; + } + g_list_free (children); - if (gtk_widget_get_visible (child->widget)) - { - if (child->pack_type == GTK_PACK_START) - have_visible_at_start = TRUE; - else - have_visible_at_end = TRUE; - } + children = gtk_container_get_children (GTK_CONTAINER (priv->end_box)); + for (l = children; l; l = l->next) + { + if (l->data != priv->titlebar_end_box && gtk_widget_get_visible (l->data)) + have_visible_at_end = TRUE; } + g_list_free (children); if (priv->titlebar_start_separator != NULL) gtk_widget_set_visible (priv->titlebar_start_separator, have_visible_at_start); @@ -490,17 +489,17 @@ _gtk_header_bar_update_window_buttons (GtkHeaderBar *bar) else gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_RIGHT); - gtk_widget_set_parent (box, GTK_WIDGET (bar)); - if (i == 0) { priv->titlebar_start_box = box; priv->titlebar_start_separator = separator; + gtk_container_add (GTK_CONTAINER (priv->start_box), box); } else { priv->titlebar_end_box = box; priv->titlebar_end_separator = separator; + gtk_container_add (GTK_CONTAINER (priv->end_box), box); } } g_strfreev (tokens); @@ -522,11 +521,46 @@ static void update_default_decoration (GtkHeaderBar *bar) { GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); + GtkLayoutManager *layout = gtk_widget_get_layout_manager (GTK_WIDGET (bar)); GtkStyleContext *context; + gboolean have_children = FALSE; + + /* Check whether we have any child widgets that we didn't add ourselves */ + if (gtk_center_layout_get_center_widget (GTK_CENTER_LAYOUT (layout)) != NULL) + { + have_children = TRUE; + } + else + { + GtkWidget *w; + + for (w = _gtk_widget_get_first_child (priv->start_box); + w != NULL; + w = _gtk_widget_get_next_sibling (w)) + { + if (w != priv->titlebar_start_box) + { + have_children = TRUE; + break; + } + } + + if (!have_children) + for (w = _gtk_widget_get_first_child (priv->end_box); + w != NULL; + w = _gtk_widget_get_next_sibling (w)) + { + if (w != priv->titlebar_end_box) + { + have_children = TRUE; + break; + } + } + } context = gtk_widget_get_style_context (GTK_WIDGET (bar)); - if (priv->children != NULL || priv->custom_title != NULL) + if (have_children || priv->custom_title != NULL) gtk_style_context_remove_class (context, "default-decoration"); else gtk_style_context_add_class (context, "default-decoration"); @@ -542,47 +576,11 @@ _gtk_header_bar_track_default_decoration (GtkHeaderBar *bar) update_default_decoration (bar); } -/* As an intended side effect, this function allows @child - * to be the title/label box */ -static void -gtk_header_bar_reorder_css_node (GtkHeaderBar *bar, - GtkPackType pack_type, - GtkWidget *widget) -{ - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GtkWidget *previous_widget; - GList *l; - - if (pack_type == GTK_PACK_START) - previous_widget = priv->titlebar_start_box; - else - previous_widget = priv->titlebar_end_box; - - for (l = priv->children; l; l = l->next) - { - Child *iter = l->data; - - if (iter->widget == widget) - break; - - if (iter->pack_type == pack_type) - previous_widget = iter->widget; - } - - if (pack_type == GTK_PACK_START) - gtk_css_node_insert_after (gtk_widget_get_css_node (GTK_WIDGET (bar)), - gtk_widget_get_css_node (widget), - previous_widget ? gtk_widget_get_css_node (previous_widget) : NULL); - else - gtk_css_node_insert_before (gtk_widget_get_css_node (GTK_WIDGET (bar)), - gtk_widget_get_css_node (widget), - previous_widget ? gtk_widget_get_css_node (previous_widget) : NULL); -} - static void construct_label_box (GtkHeaderBar *bar) { GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); + GtkLayoutManager *layout = gtk_widget_get_layout_manager (GTK_WIDGET (bar)); g_assert (priv->label_box == NULL); @@ -590,620 +588,8 @@ construct_label_box (GtkHeaderBar *bar) priv->subtitle, &priv->title_label, &priv->subtitle_label); - gtk_header_bar_reorder_css_node (bar, GTK_PACK_START, priv->label_box); - gtk_widget_set_parent (priv->label_box, GTK_WIDGET (bar)); -} - -static gint -count_visible_children (GtkHeaderBar *bar) -{ - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GList *l; - Child *child; - gint n; - - n = 0; - for (l = priv->children; l; l = l->next) - { - child = l->data; - if (gtk_widget_get_visible (child->widget)) - n++; - } - - return n; -} - -static gboolean -add_child_size (GtkWidget *child, - GtkOrientation orientation, - gint *minimum, - gint *natural) -{ - gint child_minimum, child_natural; - - if (!gtk_widget_get_visible (child)) - return FALSE; - - gtk_widget_measure (child, orientation, -1, &child_minimum, &child_natural, - NULL, NULL); - - if (GTK_ORIENTATION_HORIZONTAL == orientation) - { - *minimum += child_minimum; - *natural += child_natural; - } - else - { - *minimum = MAX (*minimum, child_minimum); - *natural = MAX (*natural, child_natural); - } - - return TRUE; -} - -static void -gtk_header_bar_get_size (GtkWidget *widget, - GtkOrientation orientation, - gint *minimum_size, - gint *natural_size) -{ - GtkHeaderBar *bar = GTK_HEADER_BAR (widget); - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GList *l; - gint nvis_children; - gint minimum, natural; - gint center_min, center_nat; - - minimum = natural = 0; - nvis_children = 0; - - for (l = priv->children; l; l = l->next) - { - Child *child = l->data; - - if (add_child_size (child->widget, orientation, &minimum, &natural)) - nvis_children += 1; - } - - center_min = center_nat = 0; - if (priv->label_box != NULL) - { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - add_child_size (priv->label_box, orientation, ¢er_min, ¢er_nat); - else - add_child_size (priv->label_sizing_box, orientation, ¢er_min, ¢er_nat); - - if (_gtk_widget_get_visible (priv->label_sizing_box)) - nvis_children += 1; - } - - if (priv->custom_title != NULL) - { - if (add_child_size (priv->custom_title, orientation, ¢er_min, ¢er_nat)) - nvis_children += 1; - } - - if (priv->titlebar_start_box != NULL) - { - if (add_child_size (priv->titlebar_start_box, orientation, &minimum, &natural)) - nvis_children += 1; - } - - if (priv->titlebar_end_box != NULL) - { - if (add_child_size (priv->titlebar_end_box, orientation, &minimum, &natural)) - nvis_children += 1; - } - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - minimum += center_min; - natural += center_nat; - } - else - { - minimum = MAX (minimum, center_min); - natural = MAX (natural, center_nat); - } - - if (nvis_children > 0 && orientation == GTK_ORIENTATION_HORIZONTAL) - { - minimum += nvis_children * priv->spacing; - natural += nvis_children * priv->spacing; - } - - *minimum_size = minimum; - *natural_size = natural; -} - -static void -gtk_header_bar_compute_size_for_orientation (GtkWidget *widget, - gint avail_size, - gint *minimum_size, - gint *natural_size) -{ - GtkHeaderBar *bar = GTK_HEADER_BAR (widget); - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GList *children; - gint required_size = 0; - gint required_natural = 0; - gint child_size; - gint child_natural; - gint nvis_children; - - nvis_children = 0; - - for (children = priv->children; children != NULL; children = children->next) - { - Child *child = children->data; - - if (gtk_widget_get_visible (child->widget)) - { - gtk_widget_measure (child->widget, GTK_ORIENTATION_HORIZONTAL, avail_size, - &child_size, &child_natural, NULL, NULL); - - required_size += child_size; - required_natural += child_natural; - - nvis_children += 1; - } - } - - if (priv->label_box != NULL) - { - gtk_widget_measure (priv->label_sizing_box, GTK_ORIENTATION_HORIZONTAL, -1, - &child_size, &child_natural, NULL, NULL); - required_size += child_size; - required_natural += child_natural; - } - - if (priv->custom_title != NULL && - gtk_widget_get_visible (priv->custom_title)) - { - gtk_widget_measure (priv->custom_title, GTK_ORIENTATION_HORIZONTAL, -1, - &child_size, &child_natural, NULL, NULL); - - required_size += child_size; - required_natural += child_natural; - } - - if (priv->titlebar_start_box != NULL) - { - gtk_widget_measure (priv->titlebar_start_box, GTK_ORIENTATION_HORIZONTAL, -1, - &child_size, &child_natural, NULL, NULL); - required_size += child_size; - required_natural += child_natural; - nvis_children += 1; - } - - if (priv->titlebar_end_box != NULL) - { - gtk_widget_measure (priv->titlebar_end_box, GTK_ORIENTATION_HORIZONTAL, -1, - &child_size, &child_natural, NULL, NULL); - - required_size += child_size; - required_natural += child_natural; - nvis_children += 1; - } - - if (nvis_children > 0) - { - required_size += nvis_children * priv->spacing; - required_natural += nvis_children * priv->spacing; - } - - *minimum_size = required_size; - *natural_size = required_natural; -} - -static void -gtk_header_bar_compute_size_for_opposing_orientation (GtkWidget *widget, - gint avail_size, - gint *minimum_size, - gint *natural_size) -{ - GtkHeaderBar *bar = GTK_HEADER_BAR (widget); - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - Child *child; - GList *children; - gint nvis_children; - gint computed_minimum = 0; - gint computed_natural = 0; - GtkRequestedSize *sizes; - GtkPackType packing; - gint size = 0; - gint i; - gint child_size; - gint child_minimum; - gint child_natural; - gint center_min, center_nat; - - nvis_children = count_visible_children (bar); - - if (nvis_children <= 0) - return; - - sizes = g_newa (GtkRequestedSize, nvis_children); - - /* Retrieve desired size for visible children */ - for (i = 0, children = priv->children; children; children = children->next) - { - child = children->data; - - if (gtk_widget_get_visible (child->widget)) - { - gtk_widget_measure (child->widget, GTK_ORIENTATION_HORIZONTAL, -1, - &sizes[i].minimum_size, &sizes[i].natural_size, - NULL, NULL); - - size -= sizes[i].minimum_size; - sizes[i].data = child; - i += 1; - } - } - - /* Bring children up to size first */ - size = gtk_distribute_natural_allocation (MAX (0, avail_size), nvis_children, sizes); - - /* Allocate child positions. */ - for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing) - { - for (i = 0, children = priv->children; children; children = children->next) - { - child = children->data; - - /* If widget is not visible, skip it. */ - if (!gtk_widget_get_visible (child->widget)) - continue; - - /* If widget is packed differently skip it, but still increment i, - * since widget is visible and will be handled in next loop - * iteration. - */ - if (child->pack_type != packing) - { - i++; - continue; - } - - child_size = sizes[i].minimum_size; - - gtk_widget_measure (child->widget, GTK_ORIENTATION_VERTICAL, child_size, - &child_minimum, &child_natural, NULL, NULL); - - computed_minimum = MAX (computed_minimum, child_minimum); - computed_natural = MAX (computed_natural, child_natural); - } - i += 1; - } - - center_min = center_nat = 0; - if (priv->label_box != NULL) - { - gtk_widget_measure (priv->label_sizing_box, GTK_ORIENTATION_VERTICAL, -1, - ¢er_min, ¢er_nat, NULL, NULL); - } - - if (priv->custom_title != NULL && - gtk_widget_get_visible (priv->custom_title)) - { - gtk_widget_measure (priv->custom_title, GTK_ORIENTATION_VERTICAL, -1, - ¢er_min, ¢er_nat, NULL, NULL); - } - - if (priv->titlebar_start_box != NULL) - { - gtk_widget_measure (priv->titlebar_start_box, GTK_ORIENTATION_VERTICAL, -1, - &child_minimum, &child_natural, NULL, NULL); - - computed_minimum = MAX (computed_minimum, child_minimum); - computed_natural = MAX (computed_natural, child_natural); - } - - if (priv->titlebar_end_box != NULL) - { - gtk_widget_measure (priv->titlebar_end_box, GTK_ORIENTATION_VERTICAL, -1, - &child_minimum, &child_natural, NULL, NULL); - - computed_minimum = MAX (computed_minimum, child_minimum); - computed_natural = MAX (computed_natural, child_natural); - } - - *minimum_size = computed_minimum; - *natural_size = computed_natural; -} - -static void -gtk_header_bar_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - int min, nat; - gtk_header_bar_get_size (widget, orientation, &min, &nat); - - if (for_size < 0) - *natural = nat; - else if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_header_bar_compute_size_for_orientation (widget, for_size, minimum, natural); - else - gtk_header_bar_compute_size_for_opposing_orientation (widget, for_size, minimum, natural); - - *minimum = MAX (*minimum, min); - *natural = MAX (*natural, min); -} - -static void -gtk_header_bar_size_allocate (GtkWidget *widget, - int widget_width, - int widget_height, - int baseline) -{ - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (GTK_HEADER_BAR (widget)); - GtkWidget *title_widget; - GtkHeaderBar *bar = GTK_HEADER_BAR (widget); - GtkRequestedSize *sizes; - gint width, height; - gint nvis_children; - gint title_minimum_size; - gint title_natural_size; - gboolean title_expands = FALSE; - gint start_width, end_width; - gint uniform_expand_bonus[2] = { 0 }; - gint leftover_expand_bonus[2] = { 0 }; - gint nexpand_children[2] = { 0 }; - gint side[2]; - GList *l; - gint i; - Child *child; - GtkPackType packing; - GtkAllocation child_allocation; - gint x; - gint child_size; - GtkTextDirection direction; - - direction = gtk_widget_get_direction (widget); - nvis_children = count_visible_children (bar); - sizes = g_newa (GtkRequestedSize, nvis_children); - - width = widget_width - nvis_children * priv->spacing; - height = widget_height; - - i = 0; - for (l = priv->children; l; l = l->next) - { - child = l->data; - if (!gtk_widget_get_visible (child->widget)) - continue; - - if (gtk_widget_compute_expand (child->widget, GTK_ORIENTATION_HORIZONTAL)) - nexpand_children[child->pack_type]++; - - gtk_widget_measure (child->widget, GTK_ORIENTATION_HORIZONTAL, height, - &sizes[i].minimum_size, &sizes[i].natural_size, - NULL, NULL); - - width -= sizes[i].minimum_size; - i++; - } - - title_minimum_size = 0; - title_natural_size = 0; - - if (priv->custom_title != NULL && - gtk_widget_get_visible (priv->custom_title)) - title_widget = priv->custom_title; - else if (priv->label_box != NULL) - title_widget = priv->label_box; - else - title_widget = NULL; - - if (title_widget) - { - gtk_widget_measure (title_widget, GTK_ORIENTATION_HORIZONTAL, height, - &title_minimum_size, &title_natural_size, - NULL, NULL); - - width -= title_natural_size; - - title_expands = gtk_widget_compute_expand (title_widget, GTK_ORIENTATION_HORIZONTAL); - } - - start_width = 0; - if (priv->titlebar_start_box != NULL) - { - gint min, nat; - gtk_widget_measure (priv->titlebar_start_box, GTK_ORIENTATION_HORIZONTAL, height, - &min, &nat, - NULL, NULL); - - start_width = nat + priv->spacing; - } - width -= start_width; - - end_width = 0; - if (priv->titlebar_end_box != NULL) - { - gint min, nat; - gtk_widget_measure (priv->titlebar_end_box, GTK_ORIENTATION_HORIZONTAL, height, - &min, &nat, - NULL, NULL); - - end_width = nat + priv->spacing; - } - width -= end_width; - - width = gtk_distribute_natural_allocation (MAX (0, width), nvis_children, sizes); - - /* compute the nominal size of the children filling up each side of - * the title in titlebar - */ - side[0] = start_width; - side[1] = end_width; - for (packing = GTK_PACK_START; packing <= GTK_PACK_END; packing++) - { - i = 0; - for (l = priv->children; l != NULL; l = l->next) - { - child = l->data; - if (!gtk_widget_get_visible (child->widget)) - continue; - - if (child->pack_type == packing) - side[packing] += sizes[i].minimum_size + priv->spacing; - - i++; - } - } - - /* figure out how much space is left on each side of the title, - * and earkmark that space for the expanded children. - * - * If the title itself is expanded, then it gets half the spoils - * from each side. - */ - for (packing = GTK_PACK_START; packing <= GTK_PACK_END; packing++) - { - gint side_free_space; - - side_free_space = widget_width / 2 - title_natural_size / 2 - side[packing]; - - if (side_free_space > 0 && nexpand_children[packing] > 0) - { - width -= side_free_space; - - if (title_expands) - side_free_space -= side_free_space / 2; - - side[packing] += side_free_space; - uniform_expand_bonus[packing] = side_free_space / nexpand_children[packing]; - leftover_expand_bonus[packing] = side_free_space % nexpand_children[packing]; - } - } - - /* allocate the children on both sides of the title */ - for (packing = GTK_PACK_START; packing <= GTK_PACK_END; packing++) - { - child_allocation.y = 0; - child_allocation.height = height; - if (packing == GTK_PACK_START) - x = start_width; - else - x = widget_width - end_width; - - i = 0; - for (l = priv->children; l != NULL; l = l->next) - { - child = l->data; - if (!gtk_widget_get_visible (child->widget)) - continue; - - if (child->pack_type != packing) - goto next; - - child_size = sizes[i].minimum_size; - - /* if this child is expanded, give it extra space from the reserves */ - if (gtk_widget_compute_expand (child->widget, GTK_ORIENTATION_HORIZONTAL)) - { - gint expand_bonus; - - expand_bonus = uniform_expand_bonus[packing]; - - if (leftover_expand_bonus[packing] > 0) - { - expand_bonus++; - leftover_expand_bonus[packing]--; - } - - child_size += expand_bonus; - } - - child_allocation.width = child_size; - - if (packing == GTK_PACK_START) - { - child_allocation.x = x; - x += child_size; - x += priv->spacing; - } - else - { - x -= child_size; - child_allocation.x = x; - x -= priv->spacing; - } - - if (direction == GTK_TEXT_DIR_RTL) - child_allocation.x = widget_width - child_allocation.x - child_allocation.width; - - gtk_widget_size_allocate (child->widget, &child_allocation, baseline); - - next: - i++; - } - } - - /* We don't enforce css borders on the center widget, to make - * title/subtitle combinations fit without growing the header - */ - child_allocation.y = 0; - child_allocation.height = widget_height; - - child_size = MIN (widget_width - side[0] - side[1], title_natural_size); - - child_allocation.x = (widget_width - child_size) / 2; - child_allocation.width = child_size; - - /* if the title widget is expanded, then grow it by all the available - * free space, and recenter it - */ - if (title_expands && width > 0) - { - child_allocation.width += width; - child_allocation.x -= width / 2; - } - - if (side[0] > child_allocation.x) - child_allocation.x = side[0]; - else if (widget_width - side[1] < child_allocation.x + child_allocation.width) - child_allocation.x = widget_width - side[1] - child_allocation.width; - - if (direction == GTK_TEXT_DIR_RTL) - child_allocation.x = widget_width - (child_allocation.x) - child_allocation.width; - - if (title_widget != NULL) - { - gtk_widget_size_allocate (title_widget, &child_allocation, baseline); - } - - child_allocation.y = 0; - child_allocation.height = height; - - if (priv->titlebar_start_box) - { - gboolean left = (direction == GTK_TEXT_DIR_LTR); - if (left) - child_allocation.x = 0; - else - child_allocation.x = widget_width - start_width + priv->spacing; - child_allocation.width = start_width - priv->spacing; - gtk_widget_size_allocate (priv->titlebar_start_box, &child_allocation, baseline); - } - - if (priv->titlebar_end_box) - { - gboolean left = (direction != GTK_TEXT_DIR_LTR); - if (left) - child_allocation.x = 0; - else - child_allocation.x = widget_width - end_width + priv->spacing; - child_allocation.width = end_width - priv->spacing; - gtk_widget_size_allocate (priv->titlebar_end_box, &child_allocation, baseline); - } + gtk_widget_insert_after (priv->label_box, GTK_WIDGET (bar), priv->start_box); + gtk_center_layout_set_center_widget (GTK_CENTER_LAYOUT (layout), priv->label_box); } /** @@ -1354,10 +740,11 @@ gtk_header_bar_set_custom_title (GtkHeaderBar *bar, if (title_widget != NULL) { + GtkLayoutManager *layout = gtk_widget_get_layout_manager (GTK_WIDGET (bar)); priv->custom_title = title_widget; - gtk_header_bar_reorder_css_node (bar, GTK_PACK_START, priv->custom_title); - gtk_widget_set_parent (priv->custom_title, GTK_WIDGET (bar)); + gtk_widget_insert_after (priv->custom_title, GTK_WIDGET (bar), priv->start_box); + gtk_center_layout_set_center_widget (GTK_CENTER_LAYOUT (layout), title_widget); if (priv->label_box != NULL) { @@ -1376,8 +763,6 @@ gtk_header_bar_set_custom_title (GtkHeaderBar *bar, construct_label_box (bar); } - gtk_widget_queue_resize (GTK_WIDGET (bar)); - g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_CUSTOM_TITLE]); } @@ -1402,9 +787,9 @@ gtk_header_bar_get_custom_title (GtkHeaderBar *bar) } static void -gtk_header_bar_destroy (GtkWidget *widget) +gtk_header_bar_dispose (GObject *object) { - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (GTK_HEADER_BAR (widget)); + GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (GTK_HEADER_BAR (object)); if (priv->label_sizing_box) { @@ -1412,33 +797,12 @@ gtk_header_bar_destroy (GtkWidget *widget) g_clear_object (&priv->label_sizing_box); } - if (priv->custom_title) - { - gtk_widget_unparent (priv->custom_title); - priv->custom_title = NULL; - } - - if (priv->label_box) - { - gtk_widget_unparent (priv->label_box); - priv->label_box = NULL; - } - - if (priv->titlebar_start_box) - { - gtk_widget_unparent (priv->titlebar_start_box); - priv->titlebar_start_box = NULL; - priv->titlebar_start_separator = NULL; - } - - if (priv->titlebar_end_box) - { - gtk_widget_unparent (priv->titlebar_end_box); - priv->titlebar_end_box = NULL; - priv->titlebar_end_separator = NULL; - } + g_clear_pointer (&priv->custom_title, gtk_widget_unparent); + g_clear_pointer (&priv->label_box, gtk_widget_unparent); + g_clear_pointer (&priv->start_box, gtk_widget_unparent); + g_clear_pointer (&priv->end_box, gtk_widget_unparent); - GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->destroy (widget); + G_OBJECT_CLASS (gtk_header_bar_parent_class)->dispose (object); } static void @@ -1570,20 +934,15 @@ gtk_header_bar_pack (GtkHeaderBar *bar, GtkPackType pack_type) { GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - Child *child; g_return_if_fail (gtk_widget_get_parent (widget) == NULL); - child = g_new (Child, 1); - child->widget = widget; - child->pack_type = pack_type; - - priv->children = g_list_append (priv->children, child); + if (pack_type == GTK_PACK_START) + gtk_container_add (GTK_CONTAINER (priv->start_box), widget); + else if (pack_type == GTK_PACK_END) + gtk_container_add (GTK_CONTAINER (priv->end_box), widget); - gtk_header_bar_reorder_css_node (bar, GTK_PACK_START, widget); - gtk_widget_set_parent (widget, GTK_WIDGET (bar)); g_signal_connect (widget, "notify::visible", G_CALLBACK (notify_child_cb), bar); - _gtk_header_bar_update_separator_visibility (bar); if (priv->track_default_decoration) @@ -1597,48 +956,37 @@ gtk_header_bar_add (GtkContainer *container, gtk_header_bar_pack (GTK_HEADER_BAR (container), child, GTK_PACK_START); } -static GList * -find_child_link (GtkHeaderBar *bar, - GtkWidget *widget, - gint *position) -{ - GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GList *l; - Child *child; - gint i; - - for (l = priv->children, i = 0; l; l = l->next, i++) - { - child = l->data; - if (child->widget == widget) - { - if (position) - *position = i; - return l; - } - } - - return NULL; -} - static void gtk_header_bar_remove (GtkContainer *container, GtkWidget *widget) { GtkHeaderBar *bar = GTK_HEADER_BAR (container); GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GList *l; - Child *child; + GtkLayoutManager *layout = gtk_widget_get_layout_manager (GTK_WIDGET (bar)); + GtkWidget *parent; + gboolean removed = FALSE; - l = find_child_link (bar, widget, NULL); - if (l) + parent = gtk_widget_get_parent (widget); + + if (parent == priv->start_box) + { + gtk_container_remove (GTK_CONTAINER (priv->start_box), widget); + removed = TRUE; + } + else if (parent == priv->end_box) + { + gtk_container_remove (GTK_CONTAINER (priv->end_box), widget); + removed = TRUE; + } + else if (parent == GTK_WIDGET (container) && + gtk_center_layout_get_center_widget (GTK_CENTER_LAYOUT (layout)) == widget) + { + gtk_widget_unparent (widget); + removed = TRUE; + } + + if (removed) { - child = l->data; - g_signal_handlers_disconnect_by_func (widget, notify_child_cb, bar); - gtk_widget_unparent (child->widget); - priv->children = g_list_delete_link (priv->children, l); - g_free (child); - gtk_widget_queue_resize (GTK_WIDGET (container)); _gtk_header_bar_update_separator_visibility (bar); if (priv->track_default_decoration) @@ -1653,28 +1001,37 @@ gtk_header_bar_forall (GtkContainer *container, { GtkHeaderBar *bar = GTK_HEADER_BAR (container); GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - Child *child; - GList *children; + GtkWidget *w; - children = priv->children; - while (children) + if (priv->start_box) { - child = children->data; - children = children->next; - if (child->pack_type == GTK_PACK_START) - (* callback) (child->widget, callback_data); + w = _gtk_widget_get_first_child (priv->start_box); + while (w != NULL) + { + GtkWidget *next = _gtk_widget_get_next_sibling (w); + + if (w != priv->titlebar_start_box) + (* callback) (w, callback_data); + + w = next; + } } if (priv->custom_title != NULL) (* callback) (priv->custom_title, callback_data); - children = priv->children; - while (children) + if (priv->end_box) { - child = children->data; - children = children->next; - if (child->pack_type == GTK_PACK_END) - (* callback) (child->widget, callback_data); + w = _gtk_widget_get_first_child (priv->end_box); + while (w != NULL) + { + GtkWidget *next = _gtk_widget_get_next_sibling (w); + + if (w != priv->titlebar_end_box) + (* callback) (w, callback_data); + + w = next; + } } } @@ -1754,13 +1111,11 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); + object_class->dispose = gtk_header_bar_dispose; object_class->finalize = gtk_header_bar_finalize; object_class->get_property = gtk_header_bar_get_property; object_class->set_property = gtk_header_bar_set_property; - widget_class->destroy = gtk_header_bar_destroy; - widget_class->size_allocate = gtk_header_bar_size_allocate; - widget_class->measure = gtk_header_bar_measure; widget_class->realize = gtk_header_bar_realize; widget_class->unrealize = gtk_header_bar_unrealize; widget_class->root = gtk_header_bar_root; @@ -1861,20 +1216,19 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class) g_object_class_install_properties (object_class, LAST_PROP, header_bar_props); gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_PANEL); + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CENTER_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("headerbar")); } static void gtk_header_bar_init (GtkHeaderBar *bar) { - GtkHeaderBarPrivate *priv; - - priv = gtk_header_bar_get_instance_private (bar); + GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); + GtkLayoutManager *layout; priv->title = NULL; priv->subtitle = NULL; priv->custom_title = NULL; - priv->children = NULL; priv->spacing = DEFAULT_SPACING; priv->has_subtitle = TRUE; priv->decoration_layout = NULL; @@ -1882,6 +1236,14 @@ gtk_header_bar_init (GtkHeaderBar *bar) priv->shows_app_menu = FALSE; priv->state = GDK_SURFACE_STATE_WITHDRAWN; + layout = gtk_widget_get_layout_manager (GTK_WIDGET (bar)); + priv->start_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_parent (priv->start_box, GTK_WIDGET (bar)); + gtk_center_layout_set_start_widget (GTK_CENTER_LAYOUT (layout), priv->start_box); + priv->end_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_parent (priv->end_box, GTK_WIDGET (bar)); + gtk_center_layout_set_end_widget (GTK_CENTER_LAYOUT (layout), priv->end_box); + init_sizing_box (bar); construct_label_box (bar); } -- 2.30.2