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
This commit is contained in:
@ -7667,6 +7667,8 @@ gtk_header_bar_set_custom_title
|
|||||||
gtk_header_bar_get_custom_title
|
gtk_header_bar_get_custom_title
|
||||||
gtk_header_bar_pack_start
|
gtk_header_bar_pack_start
|
||||||
gtk_header_bar_pack_end
|
gtk_header_bar_pack_end
|
||||||
|
gtk_header_bar_set_show_close_button
|
||||||
|
gtk_header_bar_get_show_close_button
|
||||||
|
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GTK_TYPE_HEADER_BAR
|
GTK_TYPE_HEADER_BAR
|
||||||
|
|||||||
@ -56,6 +56,8 @@ struct _GtkHeaderBarPrivate
|
|||||||
GtkWidget *label_box;
|
GtkWidget *label_box;
|
||||||
GtkWidget *label_sizing_box;
|
GtkWidget *label_sizing_box;
|
||||||
GtkWidget *custom_title;
|
GtkWidget *custom_title;
|
||||||
|
GtkWidget *close_button;
|
||||||
|
GtkWidget *separator;
|
||||||
gint spacing;
|
gint spacing;
|
||||||
gint hpadding;
|
gint hpadding;
|
||||||
gint vpadding;
|
gint vpadding;
|
||||||
@ -77,7 +79,8 @@ enum {
|
|||||||
PROP_CUSTOM_TITLE,
|
PROP_CUSTOM_TITLE,
|
||||||
PROP_SPACING,
|
PROP_SPACING,
|
||||||
PROP_HPADDING,
|
PROP_HPADDING,
|
||||||
PROP_VPADDING
|
PROP_VPADDING,
|
||||||
|
PROP_SHOW_CLOSE_BUTTON
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -202,6 +205,57 @@ _gtk_header_bar_create_title_box (const char *title,
|
|||||||
return label_box;
|
return label_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
construct_label_box (GtkHeaderBar *bar)
|
construct_label_box (GtkHeaderBar *bar)
|
||||||
{
|
{
|
||||||
@ -230,6 +284,8 @@ gtk_header_bar_init (GtkHeaderBar *bar)
|
|||||||
priv->title = NULL;
|
priv->title = NULL;
|
||||||
priv->subtitle = NULL;
|
priv->subtitle = NULL;
|
||||||
priv->custom_title = NULL;
|
priv->custom_title = NULL;
|
||||||
|
priv->close_button = NULL;
|
||||||
|
priv->separator = NULL;
|
||||||
priv->children = NULL;
|
priv->children = NULL;
|
||||||
priv->spacing = DEFAULT_SPACING;
|
priv->spacing = DEFAULT_SPACING;
|
||||||
priv->hpadding = DEFAULT_HPADDING;
|
priv->hpadding = DEFAULT_HPADDING;
|
||||||
@ -328,6 +384,15 @@ gtk_header_bar_get_size (GtkWidget *widget,
|
|||||||
nvis_children += 1;
|
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)
|
if (nvis_children > 0 && orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||||
{
|
{
|
||||||
minimum += nvis_children * priv->spacing;
|
minimum += nvis_children * priv->spacing;
|
||||||
@ -408,6 +473,19 @@ gtk_header_bar_compute_size_for_orientation (GtkWidget *widget,
|
|||||||
required_natural += child_natural;
|
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)
|
if (nvis_children > 0)
|
||||||
{
|
{
|
||||||
required_size += nvis_children * priv->spacing;
|
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);
|
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);
|
get_css_padding_and_border (widget, &css_borders);
|
||||||
|
|
||||||
computed_minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
|
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 nvis_children;
|
||||||
gint title_minimum_size;
|
gint title_minimum_size;
|
||||||
gint title_natural_size;
|
gint title_natural_size;
|
||||||
|
gint close_button_width;
|
||||||
|
gint separator_width;
|
||||||
|
gint close_width;
|
||||||
gint side[2];
|
gint side[2];
|
||||||
GList *l;
|
GList *l;
|
||||||
gint i;
|
gint i;
|
||||||
@ -636,6 +730,23 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
|
|||||||
}
|
}
|
||||||
width -= title_natural_size;
|
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);
|
width = gtk_distribute_natural_allocation (MAX (0, width), nvis_children, sizes);
|
||||||
|
|
||||||
side[0] = side[1] = 0;
|
side[0] = side[1] = 0;
|
||||||
@ -646,7 +757,7 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
|
|||||||
if (packing == GTK_PACK_START)
|
if (packing == GTK_PACK_START)
|
||||||
x = allocation->x + priv->hpadding + css_borders.left;
|
x = allocation->x + priv->hpadding + css_borders.left;
|
||||||
else
|
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)
|
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.y = allocation->y + priv->vpadding + css_borders.top;
|
||||||
child_allocation.height = height;
|
child_allocation.height = height;
|
||||||
|
|
||||||
@ -727,6 +840,23 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
|
|||||||
gtk_widget_size_allocate (priv->custom_title, &child_allocation);
|
gtk_widget_size_allocate (priv->custom_title, &child_allocation);
|
||||||
else
|
else
|
||||||
gtk_widget_size_allocate (priv->label_box, &child_allocation);
|
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);
|
g_value_set_int (value, priv->vpadding);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_SHOW_CLOSE_BUTTON:
|
||||||
|
g_value_set_boolean (value, gtk_header_bar_get_show_close_button (bar));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -1020,6 +1154,10 @@ gtk_header_bar_set_property (GObject *object,
|
|||||||
gtk_widget_queue_resize (GTK_WIDGET (bar));
|
gtk_widget_queue_resize (GTK_WIDGET (bar));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_SHOW_CLOSE_BUTTON:
|
||||||
|
gtk_header_bar_set_show_close_button (bar, g_value_get_boolean (value));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -1120,6 +1258,12 @@ gtk_header_bar_forall (GtkContainer *container,
|
|||||||
if (include_internals && priv->label_box != NULL)
|
if (include_internals && priv->label_box != NULL)
|
||||||
(* callback) (priv->label_box, callback_data);
|
(* 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;
|
children = priv->children;
|
||||||
while (children)
|
while (children)
|
||||||
{
|
{
|
||||||
@ -1362,6 +1506,14 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
|
|||||||
DEFAULT_VPADDING,
|
DEFAULT_VPADDING,
|
||||||
GTK_PARAM_READWRITE));
|
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);
|
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));
|
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");
|
||||||
|
}
|
||||||
|
|||||||
@ -83,6 +83,13 @@ GDK_AVAILABLE_IN_3_10
|
|||||||
void gtk_header_bar_pack_end (GtkHeaderBar *bar,
|
void gtk_header_bar_pack_end (GtkHeaderBar *bar,
|
||||||
GtkWidget *child);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GTK_HEADER_BAR_H__ */
|
#endif /* __GTK_HEADER_BAR_H__ */
|
||||||
|
|||||||
@ -17,7 +17,9 @@ main (int argc, char *argv[])
|
|||||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||||
|
|
||||||
header = gtk_header_bar_new ();
|
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");
|
gtk_style_context_add_class (gtk_widget_get_style_context (header), "titlebar");
|
||||||
|
|
||||||
title = gtk_label_new (NULL);
|
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_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);
|
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_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), 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);
|
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||||
gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
|
gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
|
||||||
button = gtk_button_new ();
|
button = gtk_button_new ();
|
||||||
|
|||||||
Reference in New Issue
Block a user