[gtk+] GtkHeaderBar: optionally add a close button
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] GtkHeaderBar: optionally add a close button
- Date: Sun, 4 Aug 2013 23:38:55 +0000 (UTC)
commit b38a096aee2e7486ced567adbad3177d276a8e5a
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Aug 4 01:25:26 2013 +0200
GtkHeaderBar: optionally add a close button
Add a boolean property that controls whether a window close button
will be shown in the header bar or not. Doing this in the toolkit
will ensure consistency of the visual apperance.
https://bugzilla.gnome.org/show_bug.cgi?id=702971
docs/reference/gtk/gtk3-sections.txt | 2 +
gtk/gtkheaderbar.c | 214 +++++++++++++++++++++++++++++++++-
gtk/gtkheaderbar.h | 7 +
tests/testtitlebar.c | 14 +--
4 files changed, 223 insertions(+), 14 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index d5555a2..886f4d9 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -7667,6 +7667,8 @@ gtk_header_bar_set_custom_title
gtk_header_bar_get_custom_title
gtk_header_bar_pack_start
gtk_header_bar_pack_end
+gtk_header_bar_set_show_close_button
+gtk_header_bar_get_show_close_button
<SUBSECTION Standard>
GTK_TYPE_HEADER_BAR
diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c
index a803dda..9aa55df 100644
--- a/gtk/gtkheaderbar.c
+++ b/gtk/gtkheaderbar.c
@@ -56,6 +56,8 @@ struct _GtkHeaderBarPrivate
GtkWidget *label_box;
GtkWidget *label_sizing_box;
GtkWidget *custom_title;
+ GtkWidget *close_button;
+ GtkWidget *separator;
gint spacing;
gint hpadding;
gint vpadding;
@@ -77,7 +79,8 @@ enum {
PROP_CUSTOM_TITLE,
PROP_SPACING,
PROP_HPADDING,
- PROP_VPADDING
+ PROP_VPADDING,
+ PROP_SHOW_CLOSE_BUTTON
};
enum {
@@ -203,6 +206,57 @@ _gtk_header_bar_create_title_box (const char *title,
}
static void
+close_button_clicked (GtkButton *button, gpointer data)
+{
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ gtk_window_close (GTK_WINDOW (toplevel));
+}
+
+static void
+add_close_button (GtkHeaderBar *bar)
+{
+ GtkHeaderBarPrivate *priv;
+ GtkWidget *button;
+ GIcon *icon;
+ GtkWidget *image;
+ GtkWidget *separator;
+
+ priv = gtk_header_bar_get_instance_private (bar);
+
+ button = gtk_button_new ();
+ icon = g_themed_icon_new ("window-close-symbolic");
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
+ g_object_unref (icon);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (close_button_clicked), NULL);
+ gtk_widget_show_all (button);
+ gtk_widget_set_parent (button, GTK_WIDGET (bar));
+
+ separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+ gtk_widget_show (separator);
+ gtk_widget_set_parent (separator, GTK_WIDGET (bar));
+
+ priv->separator = separator;
+ priv->close_button = button;
+}
+
+static void
+remove_close_button (GtkHeaderBar *bar)
+{
+ GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
+
+ gtk_widget_unparent (priv->separator);
+ gtk_widget_unparent (priv->close_button);
+
+ priv->separator = NULL;
+ priv->close_button = NULL;
+}
+
+static void
construct_label_box (GtkHeaderBar *bar)
{
GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
@@ -230,6 +284,8 @@ gtk_header_bar_init (GtkHeaderBar *bar)
priv->title = NULL;
priv->subtitle = NULL;
priv->custom_title = NULL;
+ priv->close_button = NULL;
+ priv->separator = NULL;
priv->children = NULL;
priv->spacing = DEFAULT_SPACING;
priv->hpadding = DEFAULT_HPADDING;
@@ -328,6 +384,15 @@ gtk_header_bar_get_size (GtkWidget *widget,
nvis_children += 1;
}
+ if (priv->close_button != NULL)
+ {
+ if (add_child_size (priv->close_button, orientation, &minimum, &natural))
+ nvis_children += 1;
+
+ if (add_child_size (priv->separator, orientation, &minimum, &natural))
+ nvis_children += 1;
+ }
+
if (nvis_children > 0 && orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum += nvis_children * priv->spacing;
@@ -408,6 +473,19 @@ gtk_header_bar_compute_size_for_orientation (GtkWidget *widget,
required_natural += child_natural;
}
+ if (priv->close_button != NULL)
+ {
+ gtk_widget_get_preferred_width (priv->close_button,
+ &child_size, &child_natural);
+ required_size += child_size;
+ required_natural += child_natural;
+
+ gtk_widget_get_preferred_width (priv->separator,
+ &child_size, &child_natural);
+ required_size += child_size;
+ required_natural += child_natural;
+ }
+
if (nvis_children > 0)
{
required_size += nvis_children * priv->spacing;
@@ -526,6 +604,19 @@ gtk_header_bar_compute_size_for_opposing_orientation (GtkWidget *widget,
computed_natural = MAX (computed_natural, child_natural);
}
+ if (priv->close_button != NULL)
+ {
+ gtk_widget_get_preferred_height (priv->close_button,
+ &child_minimum, &child_natural);
+ computed_minimum = MAX (computed_minimum, child_minimum);
+ computed_natural = MAX (computed_natural, child_natural);
+
+ gtk_widget_get_preferred_height (priv->separator,
+ &child_minimum, &child_natural);
+ computed_minimum = MAX (computed_minimum, child_minimum);
+ computed_natural = MAX (computed_natural, child_natural);
+ }
+
get_css_padding_and_border (widget, &css_borders);
computed_minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
@@ -583,6 +674,9 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
gint nvis_children;
gint title_minimum_size;
gint title_natural_size;
+ gint close_button_width;
+ gint separator_width;
+ gint close_width;
gint side[2];
GList *l;
gint i;
@@ -636,6 +730,23 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
}
width -= title_natural_size;
+ close_button_width = separator_width = close_width = 0;
+ if (priv->close_button != NULL)
+ {
+ gint min, nat;
+ gtk_widget_get_preferred_width_for_height (priv->close_button,
+ height,
+ &min, &nat);
+ close_button_width = nat;
+
+ gtk_widget_get_preferred_width_for_height (priv->separator,
+ height,
+ &min, &nat);
+ separator_width = nat;
+ close_width = close_button_width + separator_width + 2 * priv->spacing;
+ }
+ width -= close_width;
+
width = gtk_distribute_natural_allocation (MAX (0, width), nvis_children, sizes);
side[0] = side[1] = 0;
@@ -646,7 +757,7 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
if (packing == GTK_PACK_START)
x = allocation->x + priv->hpadding + css_borders.left;
else
- x = allocation->x + allocation->width - priv->hpadding - css_borders.right;
+ x = allocation->x + allocation->width - close_width - priv->hpadding - css_borders.right;
if (packing == GTK_PACK_START)
{
@@ -700,6 +811,8 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
}
}
+ side[GTK_PACK_END] += close_width;
+
child_allocation.y = allocation->y + priv->vpadding + css_borders.top;
child_allocation.height = height;
@@ -727,6 +840,23 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (priv->custom_title, &child_allocation);
else
gtk_widget_size_allocate (priv->label_box, &child_allocation);
+
+ if (priv->close_button)
+ {
+ if (direction == GTK_TEXT_DIR_RTL)
+ child_allocation.x = allocation->x + priv->hpadding + css_borders.left;
+ else
+ child_allocation.x = allocation->x + allocation->width - priv->hpadding - css_borders.right -
close_button_width;
+ child_allocation.width = close_button_width;
+ gtk_widget_size_allocate (priv->close_button, &child_allocation);
+
+ if (direction == GTK_TEXT_DIR_RTL)
+ child_allocation.x = allocation->x + priv->hpadding + css_borders.left + close_button_width +
priv->spacing;
+ else
+ child_allocation.x = allocation->x + allocation->width - priv->hpadding - css_borders.right -
close_button_width - priv->spacing - separator_width;
+ child_allocation.width = separator_width;
+ gtk_widget_size_allocate (priv->separator, &child_allocation);
+ }
}
/**
@@ -976,6 +1106,10 @@ gtk_header_bar_get_property (GObject *object,
g_value_set_int (value, priv->vpadding);
break;
+ case PROP_SHOW_CLOSE_BUTTON:
+ g_value_set_boolean (value, gtk_header_bar_get_show_close_button (bar));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1020,6 +1154,10 @@ gtk_header_bar_set_property (GObject *object,
gtk_widget_queue_resize (GTK_WIDGET (bar));
break;
+ case PROP_SHOW_CLOSE_BUTTON:
+ gtk_header_bar_set_show_close_button (bar, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1120,6 +1258,12 @@ gtk_header_bar_forall (GtkContainer *container,
if (include_internals && priv->label_box != NULL)
(* callback) (priv->label_box, callback_data);
+ if (include_internals && priv->close_button != NULL)
+ (* callback) (priv->close_button, callback_data);
+
+ if (include_internals && priv->separator != NULL)
+ (* callback) (priv->separator, callback_data);
+
children = priv->children;
while (children)
{
@@ -1362,6 +1506,14 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
DEFAULT_VPADDING,
GTK_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SHOW_CLOSE_BUTTON,
+ g_param_spec_boolean ("show-close-button",
+ P_("Show Close button"),
+ P_("Whether to show a window close button"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_FILLER);
}
@@ -1433,3 +1585,61 @@ gtk_header_bar_new (void)
{
return GTK_WIDGET (g_object_new (GTK_TYPE_HEADER_BAR, NULL));
}
+
+/**
+ * gtk_header_bar_get_show_close_button:
+ * @bar: a #GtkHeaderBar
+ *
+ * Returns whether this header bar shows a window close
+ * button.
+ *
+ * Returns: %TRUE if a window close button is shown
+ *
+ * Since: 3.10
+ */
+gboolean
+gtk_header_bar_get_show_close_button (GtkHeaderBar *bar)
+{
+ GtkHeaderBarPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), FALSE);
+
+ priv = gtk_header_bar_get_instance_private (bar);
+
+ return priv->close_button != NULL;
+}
+
+/**
+ * gtk_header_bar_set_show_close_button:
+ * @bar: a #GtkHeaderBar
+ * @setting: %TRUE to show a window close button
+ *
+ * Sets whether this header bar shows a window close
+ * button.
+ *
+ * Since: 3.10
+ */
+void
+gtk_header_bar_set_show_close_button (GtkHeaderBar *bar,
+ gboolean setting)
+{
+ GtkHeaderBarPrivate *priv;
+
+ g_return_if_fail (GTK_IS_HEADER_BAR (bar));
+
+ priv = gtk_header_bar_get_instance_private (bar);
+
+ setting = setting != FALSE;
+
+ if ((priv->close_button != NULL) == setting)
+ return;
+
+ if (setting)
+ add_close_button (bar);
+ else
+ remove_close_button (bar);
+
+ gtk_widget_queue_resize (GTK_WIDGET (bar));
+
+ g_object_notify (G_OBJECT (bar), "show-close-button");
+}
diff --git a/gtk/gtkheaderbar.h b/gtk/gtkheaderbar.h
index 0437ba0..0e4f5e2 100644
--- a/gtk/gtkheaderbar.h
+++ b/gtk/gtkheaderbar.h
@@ -83,6 +83,13 @@ GDK_AVAILABLE_IN_3_10
void gtk_header_bar_pack_end (GtkHeaderBar *bar,
GtkWidget *child);
+GDK_AVAILABLE_IN_3_10
+gboolean gtk_header_bar_get_show_close_button (GtkHeaderBar *bar);
+
+GDK_AVAILABLE_IN_3_10
+void gtk_header_bar_set_show_close_button (GtkHeaderBar *bar,
+ gboolean setting);
+
G_END_DECLS
#endif /* __GTK_HEADER_BAR_H__ */
diff --git a/tests/testtitlebar.c b/tests/testtitlebar.c
index e20c394..107f705 100644
--- a/tests/testtitlebar.c
+++ b/tests/testtitlebar.c
@@ -17,7 +17,9 @@ main (int argc, char *argv[])
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
header = gtk_header_bar_new ();
+ gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (header), TRUE);
gtk_style_context_add_class (gtk_widget_get_style_context (header), "titlebar");
+
title = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (title), "<b>Welcome to Facebook - Log in, sign up or learn more</b>");
gtk_label_set_ellipsize (GTK_LABEL (title), PANGO_ELLIPSIZE_END);
@@ -32,18 +34,6 @@ main (int argc, char *argv[])
gtk_container_add (GTK_CONTAINER (button), image);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
- gtk_header_bar_pack_end (GTK_HEADER_BAR (header), gtk_separator_new (GTK_ORIENTATION_VERTICAL));
-
- button = gtk_button_new ();
- icon = g_themed_icon_new ("window-close-symbolic");
- image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
- g_object_unref (icon);
- gtk_container_add (GTK_CONTAINER (button), image);
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_close), window);
-
- gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
-
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
button = gtk_button_new ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]