2
* Copyright (c) 2013 Red Hat, Inc.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or (at your
7
* option) any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12
* License for more details.
14
* You should have received a copy of the GNU Lesser General Public License
15
* along with this program; if not, write to the Free Software Foundation,
16
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
#include "gd-header-bar.h"
28
#define DEFAULT_SPACING 8
29
#define DEFAULT_HPADDING 8
30
#define DEFAULT_VPADDING 6
32
struct _GdHeaderBarPrivate
37
GtkWidget *title_label;
38
GtkWidget *subtitle_label;
39
GtkWidget *labels_box;
40
GtkWidget *labels_sizing_box;
42
GtkWidget *custom_title;
43
GdkWindow *event_window;
51
typedef struct _Child Child;
55
GtkPackType pack_type;
74
static void gd_header_buildable_init (GtkBuildableIface *iface);
76
G_DEFINE_TYPE_WITH_CODE (GdHeaderBar, gd_header_bar, GTK_TYPE_CONTAINER,
77
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
78
gd_header_buildable_init));
81
boldify_label (GtkWidget *label)
84
attrs = pango_attr_list_new ();
85
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
86
gtk_label_set_attributes (GTK_LABEL (label), attrs);
87
pango_attr_list_unref (attrs);
91
smallify_label (GtkWidget *label)
94
attrs = pango_attr_list_new ();
95
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
96
gtk_label_set_attributes (GTK_LABEL (label), attrs);
97
pango_attr_list_unref (attrs);
99
gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
103
get_css_padding_and_border (GtkWidget *widget,
106
GtkStyleContext *context;
110
context = gtk_widget_get_style_context (widget);
111
state = gtk_widget_get_state_flags (widget);
113
gtk_style_context_get_padding (context, state, border);
114
gtk_style_context_get_border (context, state, &tmp);
115
border->top += tmp.top;
116
border->right += tmp.right;
117
border->bottom += tmp.bottom;
118
border->left += tmp.left;
122
init_sizing_box (GdHeaderBar *bar)
124
GdHeaderBarPrivate *priv = bar->priv;
127
/* We use this box to always request size for the two labels (title and subtitle)
128
* as if they were always visible, but then allocate the real label box
129
* with its actual size, to keep it center-aligned in case we have only the title.
131
priv->labels_sizing_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
133
w = gtk_label_new (NULL);
135
gtk_box_pack_start (GTK_BOX (priv->labels_sizing_box), w, FALSE, FALSE, 0);
136
gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
137
gtk_label_set_single_line_mode (GTK_LABEL (w), TRUE);
138
gtk_label_set_ellipsize (GTK_LABEL (w), PANGO_ELLIPSIZE_END);
140
w = gtk_label_new (NULL);
142
gtk_box_pack_start (GTK_BOX (priv->labels_sizing_box), w, FALSE, FALSE, 0);
143
gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
144
gtk_label_set_single_line_mode (GTK_LABEL (w), TRUE);
145
gtk_label_set_ellipsize (GTK_LABEL (w), PANGO_ELLIPSIZE_END);
147
gtk_widget_show_all (priv->labels_sizing_box);
151
gd_header_bar_init (GdHeaderBar *bar)
153
GtkStyleContext *context;
154
GdHeaderBarPrivate *priv;
156
priv = G_TYPE_INSTANCE_GET_PRIVATE (bar, GD_TYPE_HEADER_BAR, GdHeaderBarPrivate);
159
gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
160
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (bar), FALSE);
162
priv->labels_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
163
gtk_widget_set_parent (priv->labels_box, GTK_WIDGET (bar));
164
gtk_widget_set_valign (priv->labels_box, GTK_ALIGN_CENTER);
165
gtk_widget_show (priv->labels_box);
167
init_sizing_box (bar);
169
priv->title_label = gtk_label_new ("");
170
boldify_label (priv->title_label);
171
gtk_box_pack_start (GTK_BOX (priv->labels_box), priv->title_label, FALSE, FALSE, 0);
172
gtk_label_set_line_wrap (GTK_LABEL (priv->title_label), FALSE);
173
gtk_label_set_single_line_mode (GTK_LABEL (priv->title_label), TRUE);
174
gtk_label_set_ellipsize (GTK_LABEL (priv->title_label), PANGO_ELLIPSIZE_END);
175
gtk_widget_show (priv->title_label);
177
priv->subtitle_label = gtk_label_new ("");
178
smallify_label (priv->subtitle_label);
179
gtk_box_pack_start (GTK_BOX (priv->labels_box), priv->subtitle_label, FALSE, FALSE, 0);
180
gtk_label_set_line_wrap (GTK_LABEL (priv->subtitle_label), FALSE);
181
gtk_label_set_single_line_mode (GTK_LABEL (priv->subtitle_label), TRUE);
182
gtk_label_set_ellipsize (GTK_LABEL (priv->subtitle_label), PANGO_ELLIPSIZE_END);
185
priv->custom_title = NULL;
186
priv->children = NULL;
187
priv->spacing = DEFAULT_SPACING;
188
priv->hpadding = DEFAULT_HPADDING;
189
priv->vpadding = DEFAULT_VPADDING;
191
context = gtk_widget_get_style_context (GTK_WIDGET (bar));
192
gtk_style_context_add_class (context, "header-bar");
193
gtk_style_context_add_class (context, GTK_STYLE_CLASS_HORIZONTAL);
197
count_visible_children (GdHeaderBar *bar)
204
for (l = bar->priv->children; l; l = l->next)
207
if (gtk_widget_get_visible (child->widget))
215
gd_header_bar_get_size (GtkWidget *widget,
216
GtkOrientation orientation,
220
GdHeaderBar *bar = GD_HEADER_BAR (widget);
221
GdHeaderBarPrivate *priv = bar->priv;
224
gint minimum, natural;
225
GtkBorder css_borders;
227
minimum = natural = 0;
230
if (orientation == GTK_ORIENTATION_HORIZONTAL)
231
gtk_widget_get_preferred_width (priv->labels_sizing_box,
234
gtk_widget_get_preferred_height (priv->labels_sizing_box,
237
for (l = priv->children; l; l = l->next)
239
Child *child = l->data;
241
if (gtk_widget_get_visible (child->widget))
243
gint child_minimum, child_natural;
245
if (orientation == GTK_ORIENTATION_HORIZONTAL)
246
gtk_widget_get_preferred_width (child->widget,
247
&child_minimum, &child_natural);
249
gtk_widget_get_preferred_height (child->widget,
250
&child_minimum, &child_natural);
252
if (GTK_ORIENTATION_HORIZONTAL == orientation)
254
minimum += child_minimum;
255
natural += child_natural;
259
minimum = MAX (minimum, child_minimum);
260
natural = MAX (natural, child_natural);
266
if (nvis_children > 0 && orientation == GTK_ORIENTATION_HORIZONTAL)
268
minimum += nvis_children * priv->spacing;
269
natural += nvis_children * priv->spacing;
272
get_css_padding_and_border (widget, &css_borders);
274
if (GTK_ORIENTATION_HORIZONTAL == orientation)
276
minimum += 2 * priv->hpadding + css_borders.left + css_borders.right;
277
natural += 2 * priv->hpadding + css_borders.left + css_borders.right;
281
minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
282
natural += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
286
*minimum_size = minimum;
289
*natural_size = natural;
293
gd_header_bar_compute_size_for_orientation (GtkWidget *widget,
298
GdHeaderBar *bar = GD_HEADER_BAR (widget);
299
GdHeaderBarPrivate *priv = bar->priv;
301
gint required_size = 0;
302
gint required_natural = 0;
306
GtkBorder css_borders;
308
avail_size -= 2 * priv->vpadding;
312
for (children = priv->children; children != NULL; children = children->next)
314
Child *child = children->data;
316
if (gtk_widget_get_visible (child->widget))
318
gtk_widget_get_preferred_width_for_height (child->widget,
319
avail_size, &child_size, &child_natural);
321
required_size += child_size;
322
required_natural += child_natural;
328
gtk_widget_get_preferred_width (priv->labels_sizing_box,
329
&child_size, &child_natural);
330
required_size += child_size;
331
required_natural += child_natural;
333
if (nvis_children > 0)
335
required_size += nvis_children * priv->spacing;
336
required_natural += nvis_children * priv->spacing;
339
get_css_padding_and_border (widget, &css_borders);
341
required_size += 2 * priv->hpadding + css_borders.left + css_borders.right;
342
required_natural += 2 * priv->hpadding + css_borders.left + css_borders.right;
345
*minimum_size = required_size;
348
*natural_size = required_natural;
352
gd_header_bar_compute_size_for_opposing_orientation (GtkWidget *widget,
357
GdHeaderBar *bar = GD_HEADER_BAR (widget);
358
GdHeaderBarPrivate *priv = bar->priv;
362
gint computed_minimum = 0;
363
gint computed_natural = 0;
364
GtkRequestedSize *sizes;
371
GtkBorder css_borders;
373
nvis_children = count_visible_children (bar);
375
if (nvis_children <= 0)
378
sizes = g_newa (GtkRequestedSize, nvis_children);
379
size = avail_size - 2 * priv->hpadding;
381
/* Retrieve desired size for visible children */
382
for (i = 0, children = priv->children; children; children = children->next)
384
child = children->data;
386
if (gtk_widget_get_visible (child->widget))
388
gtk_widget_get_preferred_width (child->widget,
389
&sizes[i].minimum_size,
390
&sizes[i].natural_size);
392
size -= sizes[i].minimum_size;
393
sizes[i].data = child;
398
/* Bring children up to size first */
399
size = gtk_distribute_natural_allocation (MAX (0, size), nvis_children, sizes);
401
/* Allocate child positions. */
402
for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
404
for (i = 0, children = priv->children; children; children = children->next)
406
child = children->data;
408
/* If widget is not visible, skip it. */
409
if (!gtk_widget_get_visible (child->widget))
412
/* If widget is packed differently skip it, but still increment i,
413
* since widget is visible and will be handled in next loop
416
if (child->pack_type != packing)
422
child_size = sizes[i].minimum_size;
424
gtk_widget_get_preferred_height_for_width (child->widget,
425
child_size, &child_minimum, &child_natural);
427
computed_minimum = MAX (computed_minimum, child_minimum);
428
computed_natural = MAX (computed_natural, child_natural);
433
gtk_widget_get_preferred_height (priv->labels_sizing_box,
434
&child_minimum, &child_natural);
435
computed_minimum = MAX (computed_minimum, child_minimum);
436
computed_natural = MAX (computed_natural, child_natural);
438
get_css_padding_and_border (widget, &css_borders);
440
computed_minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
441
computed_natural += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
444
*minimum_size = computed_minimum;
447
*natural_size = computed_natural;
451
gd_header_bar_get_preferred_width (GtkWidget *widget,
455
gd_header_bar_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
459
gd_header_bar_get_preferred_height (GtkWidget *widget,
463
gd_header_bar_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
467
gd_header_bar_get_preferred_width_for_height (GtkWidget *widget,
472
gd_header_bar_compute_size_for_orientation (widget, height, minimum_width, natural_width);
476
gd_header_bar_get_preferred_height_for_width (GtkWidget *widget,
478
gint *minimum_height,
479
gint *natural_height)
481
gd_header_bar_compute_size_for_opposing_orientation (widget, width, minimum_height, natural_height);
485
gd_header_bar_size_allocate (GtkWidget *widget,
486
GtkAllocation *allocation)
488
GdHeaderBar *bar = GD_HEADER_BAR (widget);
489
GdHeaderBarPrivate *priv = bar->priv;
490
GtkRequestedSize *sizes;
493
gint title_minimum_size;
494
gint title_natural_size;
500
GtkAllocation child_allocation;
503
GtkTextDirection direction;
504
GtkBorder css_borders;
506
gtk_widget_set_allocation (widget, allocation);
508
if (gtk_widget_get_realized (widget))
509
gdk_window_move_resize (priv->event_window,
515
direction = gtk_widget_get_direction (widget);
516
nvis_children = count_visible_children (bar);
517
sizes = g_newa (GtkRequestedSize, nvis_children);
519
get_css_padding_and_border (widget, &css_borders);
520
width = allocation->width - nvis_children * priv->spacing -
521
2 * priv->hpadding - css_borders.left - css_borders.right;
522
height = allocation->height - 2 * priv->vpadding - css_borders.top - css_borders.bottom;
525
for (l = priv->children; l; l = l->next)
528
if (!gtk_widget_get_visible (child->widget))
531
gtk_widget_get_preferred_width_for_height (child->widget,
533
&sizes[i].minimum_size,
534
&sizes[i].natural_size);
535
width -= sizes[i].minimum_size;
539
if (priv->custom_title)
541
gtk_widget_get_preferred_width_for_height (priv->custom_title,
544
&title_natural_size);
548
gtk_widget_get_preferred_width_for_height (priv->labels_box,
551
&title_natural_size);
553
width -= title_natural_size;
555
width = gtk_distribute_natural_allocation (MAX (0, width), nvis_children, sizes);
557
side[0] = side[1] = 0;
558
for (packing = GTK_PACK_START; packing <= GTK_PACK_END; packing++)
560
child_allocation.y = allocation->y + priv->vpadding + css_borders.top;
561
child_allocation.height = height;
562
if (packing == GTK_PACK_START)
563
x = allocation->x + priv->hpadding + css_borders.left;
565
x = allocation->x + allocation->width - priv->hpadding - css_borders.right;
567
if (packing == GTK_PACK_START)
574
l = g_list_last (priv->children);
575
i = nvis_children - 1;
578
for (; l != NULL; (packing == GTK_PACK_START) ? (l = l->next) : (l = l->prev))
581
if (!gtk_widget_get_visible (child->widget))
584
if (child->pack_type != packing)
587
child_size = sizes[i].minimum_size;
589
child_allocation.width = child_size;
591
if (packing == GTK_PACK_START)
593
child_allocation.x = x;
600
child_allocation.x = x;
604
side[packing] += child_size + priv->spacing;
606
if (direction == GTK_TEXT_DIR_RTL)
607
child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
609
gtk_widget_size_allocate (child->widget, &child_allocation);
612
if (packing == GTK_PACK_START)
619
child_allocation.y = allocation->y + priv->vpadding + css_borders.top;
620
child_allocation.height = height;
622
width = MAX(side[0], side[1]);
624
if (allocation->width - 2 * width >= title_natural_size)
625
child_size = MIN (title_natural_size, allocation->width - 2 * width);
626
else if (allocation->width - side[0] - side[1] >= title_natural_size)
627
child_size = MIN (title_natural_size, allocation->width - side[0] - side[1]);
629
child_size = allocation->width - side[0] - side[1];
631
child_allocation.x = allocation->x + (allocation->width - child_size) / 2;
632
child_allocation.width = child_size;
634
if (allocation->x + side[0] > child_allocation.x)
635
child_allocation.x = allocation->x + side[0];
636
else if (allocation->x + allocation->width - side[1] < child_allocation.x + child_allocation.width)
637
child_allocation.x = allocation->x + allocation->width - side[1] - child_allocation.width;
639
if (direction == GTK_TEXT_DIR_RTL)
640
child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
642
if (priv->custom_title)
643
gtk_widget_size_allocate (priv->custom_title, &child_allocation);
645
gtk_widget_size_allocate (priv->labels_box, &child_allocation);
649
* gd_header_bar_set_title:
650
* @bar: a #GdHeaderBar
651
* @title: (allow-none): a title
653
* Sets the title of the #GdHeaderBar. The title should help a user
654
* identify the current view. A good title should not include the
659
gd_header_bar_set_title (GdHeaderBar *bar,
662
GdHeaderBarPrivate *priv;
665
g_return_if_fail (GD_IS_HEADER_BAR (bar));
669
new_title = g_strdup (title);
670
g_free (priv->title);
671
priv->title = new_title;
673
gtk_label_set_label (GTK_LABEL (priv->title_label), priv->title);
674
gtk_widget_queue_resize (GTK_WIDGET (bar));
676
g_object_notify (G_OBJECT (bar), "title");
680
* gd_header_bar_get_title:
681
* @bar: a #GdHeaderBar
683
* Retrieves the title of the header. See gd_header_bar_set_title().
685
* Return value: the title of the header, or %NULL if none has
686
* been set explicitely. The returned string is owned by the widget
687
* and must not be modified or freed.
690
gd_header_bar_get_title (GdHeaderBar *bar)
692
g_return_val_if_fail (GD_IS_HEADER_BAR (bar), NULL);
694
return bar->priv->title;
698
* gd_header_bar_set_subtitle:
699
* @bar: a #GdHeaderBar
700
* @subtitle: (allow-none): a subtitle
702
* Sets the subtitle of the #GdHeaderBar. The subtitle should give a user
703
* an additional detail to help him identify the current view.
707
gd_header_bar_set_subtitle (GdHeaderBar *bar,
708
const gchar *subtitle)
710
GdHeaderBarPrivate *priv;
713
g_return_if_fail (GD_IS_HEADER_BAR (bar));
717
new_subtitle = g_strdup (subtitle);
718
g_free (priv->subtitle);
719
priv->subtitle = new_subtitle;
721
gtk_label_set_label (GTK_LABEL (priv->subtitle_label), priv->subtitle);
722
gtk_widget_set_visible (priv->subtitle_label, (priv->subtitle != NULL));
724
gtk_widget_queue_resize (GTK_WIDGET (bar));
726
g_object_notify (G_OBJECT (bar), "subtitle");
730
* gd_header_bar_get_subtitle:
731
* @bar: a #GdHeaderBar
733
* Retrieves the subtitle of the header. See gd_header_bar_set_subtitle().
735
* Return value: the subtitle of the header, or %NULL if none has
736
* been set explicitely. The returned string is owned by the widget
737
* and must not be modified or freed.
740
gd_header_bar_get_subtitle (GdHeaderBar *bar)
742
g_return_val_if_fail (GD_IS_HEADER_BAR (bar), NULL);
744
return bar->priv->subtitle;
748
* gd_header_bar_set_custom_title:
749
* @bar: a #GdHeaderBar
750
* @title_widget: (allow-none): a custom widget to use for a title
752
* Sets a custom title for the #GdHeaderBar. The title should help a
753
* user identify the current view. This supercedes any title set by
754
* gd_header_bar_set_title(). You should set the custom title to %NULL,
755
* for the header title label to be visible again.
759
gd_header_bar_set_custom_title (GdHeaderBar *bar,
760
GtkWidget *title_widget)
762
GdHeaderBarPrivate *priv;
764
g_return_if_fail (GD_IS_HEADER_BAR (bar));
766
g_return_if_fail (GTK_IS_WIDGET (title_widget));
770
/* No need to do anything if the custom widget stays the same */
771
if (priv->custom_title == title_widget)
774
if (priv->custom_title)
776
GtkWidget *custom = priv->custom_title;
778
priv->custom_title = NULL;
779
gtk_widget_unparent (custom);
780
g_object_unref (custom);
785
priv->custom_title = g_object_ref (title_widget);
787
gtk_widget_hide (priv->labels_box);
789
gtk_widget_set_parent (priv->custom_title, GTK_WIDGET (bar));
790
gtk_widget_set_valign (priv->custom_title, GTK_ALIGN_CENTER);
792
gtk_widget_show (title_widget);
796
gtk_widget_show (priv->labels_box);
799
gtk_widget_queue_resize (GTK_WIDGET (bar));
801
g_object_notify (G_OBJECT (bar), "custom-title");
805
* gd_header_bar_get_custom_title:
806
* @bar: a #GdHeaderBar
808
* Retrieves the custom title widget of the header. See
809
* gd_header_bar_set_custom_title().
811
* Return value: (transfer none): the custom title widget of the header, or %NULL if
812
* none has been set explicitely.
815
gd_header_bar_get_custom_title (GdHeaderBar *bar)
817
g_return_val_if_fail (GD_IS_HEADER_BAR (bar), NULL);
819
return bar->priv->custom_title;
823
gd_header_bar_finalize (GObject *object)
825
GdHeaderBar *bar = GD_HEADER_BAR (object);
826
GdHeaderBarPrivate *priv = bar->priv;
828
g_free (priv->title);
829
g_free (priv->subtitle);
831
g_list_free (priv->children);
833
G_OBJECT_CLASS (gd_header_bar_parent_class)->finalize (object);
837
gd_header_bar_get_property (GObject *object,
842
GdHeaderBar *bar = GD_HEADER_BAR (object);
843
GdHeaderBarPrivate *priv = bar->priv;
848
g_value_set_string (value, priv->title);
852
g_value_set_string (value, priv->subtitle);
855
case PROP_CUSTOM_TITLE:
856
g_value_set_object (value, priv->custom_title);
860
g_value_set_int (value, priv->spacing);
864
g_value_set_int (value, priv->hpadding);
868
g_value_set_int (value, priv->vpadding);
872
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
878
gd_header_bar_set_property (GObject *object,
883
GdHeaderBar *bar = GD_HEADER_BAR (object);
884
GdHeaderBarPrivate *priv = bar->priv;
889
gd_header_bar_set_title (bar, g_value_get_string (value));
893
gd_header_bar_set_subtitle (bar, g_value_get_string (value));
896
case PROP_CUSTOM_TITLE:
897
gd_header_bar_set_custom_title (bar, g_value_get_object (value));
901
priv->spacing = g_value_get_int (value);
902
gtk_widget_queue_resize (GTK_WIDGET (bar));
906
priv->hpadding = g_value_get_int (value);
907
gtk_widget_queue_resize (GTK_WIDGET (bar));
911
priv->vpadding = g_value_get_int (value);
912
gtk_widget_queue_resize (GTK_WIDGET (bar));
916
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
922
gd_header_bar_pack (GdHeaderBar *bar,
924
GtkPackType pack_type)
928
g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
930
child = g_new (Child, 1);
931
child->widget = widget;
932
child->pack_type = pack_type;
934
bar->priv->children = g_list_append (bar->priv->children, child);
936
gtk_widget_freeze_child_notify (widget);
937
gtk_widget_set_parent (widget, GTK_WIDGET (bar));
938
gtk_widget_child_notify (widget, "pack-type");
939
gtk_widget_child_notify (widget, "position");
940
gtk_widget_thaw_child_notify (widget);
944
gd_header_bar_add (GtkContainer *container,
947
gd_header_bar_pack (GD_HEADER_BAR (container), child, GTK_PACK_START);
951
find_child_link (GdHeaderBar *bar,
957
for (l = bar->priv->children; l; l = l->next)
960
if (child->widget == widget)
968
gd_header_bar_remove (GtkContainer *container,
971
GdHeaderBar *bar = GD_HEADER_BAR (container);
975
l = find_child_link (bar, widget);
979
gtk_widget_unparent (child->widget);
980
bar->priv->children = g_list_remove_link (bar->priv->children, l);
982
gtk_widget_queue_resize (GTK_WIDGET (container));
987
gd_header_bar_forall (GtkContainer *container,
988
gboolean include_internals,
989
GtkCallback callback,
990
gpointer callback_data)
992
GdHeaderBar *bar = GD_HEADER_BAR (container);
993
GdHeaderBarPrivate *priv = bar->priv;
997
children = priv->children;
1000
child = children->data;
1001
children = children->next;
1002
if (child->pack_type == GTK_PACK_START)
1003
(* callback) (child->widget, callback_data);
1006
if (include_internals)
1008
if (priv->custom_title)
1009
(* callback) (priv->custom_title, callback_data);
1011
(* callback) (priv->labels_box, callback_data);
1014
children = g_list_last (priv->children);
1017
child = children->data;
1018
children = children->prev;
1019
if (child->pack_type == GTK_PACK_END)
1020
(* callback) (child->widget, callback_data);
1025
gd_header_bar_child_type (GtkContainer *container)
1027
return GTK_TYPE_WIDGET;
1031
gd_header_bar_get_child_property (GtkContainer *container,
1040
l = find_child_link (GD_HEADER_BAR (container), widget);
1043
switch (property_id)
1045
case CHILD_PROP_PACK_TYPE:
1046
g_value_set_enum (value, child->pack_type);
1049
case CHILD_PROP_POSITION:
1050
g_value_set_int (value, g_list_position (GD_HEADER_BAR (container)->priv->children, l));
1054
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1060
gd_header_bar_set_child_property (GtkContainer *container,
1063
const GValue *value,
1069
l = find_child_link (GD_HEADER_BAR (container), widget);
1072
switch (property_id)
1074
case CHILD_PROP_PACK_TYPE:
1075
child->pack_type = g_value_get_enum (value);
1078
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1084
gd_header_bar_button_press (GtkWidget *toolbar,
1085
GdkEventButton *event)
1089
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
1097
if (event->type != GDK_BUTTON_PRESS)
1100
window = gtk_widget_get_toplevel (toolbar);
1104
gtk_window_begin_move_drag (GTK_WINDOW (window),
1117
gd_header_bar_realize (GtkWidget *widget)
1119
GdHeaderBar *bar = GD_HEADER_BAR (widget);
1120
GdHeaderBarPrivate *priv = bar->priv;
1121
GtkAllocation allocation;
1123
GdkWindowAttr attributes;
1124
gint attributes_mask;
1126
gtk_widget_get_allocation (widget, &allocation);
1127
gtk_widget_set_realized (widget, TRUE);
1129
attributes.window_type = GDK_WINDOW_CHILD;
1130
attributes.x = allocation.x;
1131
attributes.y = allocation.y;
1132
attributes.width = allocation.width;
1133
attributes.height = allocation.height;
1134
attributes.wclass = GDK_INPUT_ONLY;
1135
attributes.event_mask = gtk_widget_get_events (widget);
1136
attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1137
GDK_BUTTON_RELEASE_MASK |
1139
attributes_mask = GDK_WA_X | GDK_WA_Y;
1141
window = gtk_widget_get_parent_window (widget);
1142
gtk_widget_set_window (widget, window);
1143
g_object_ref (window);
1145
priv->event_window = gdk_window_new (window,
1146
&attributes, attributes_mask);
1147
gdk_window_set_user_data (priv->event_window, widget);
1150
gd_header_bar_unrealize (GtkWidget *widget)
1152
GdHeaderBar *bar = GD_HEADER_BAR (widget);
1153
GdHeaderBarPrivate *priv = bar->priv;
1155
if (priv->event_window)
1157
gdk_window_set_user_data (priv->event_window, NULL);
1158
gdk_window_destroy (priv->event_window);
1159
priv->event_window = NULL;
1162
GTK_WIDGET_CLASS (gd_header_bar_parent_class)->unrealize (widget);
1166
gd_header_bar_map (GtkWidget *widget)
1168
GdHeaderBar *bar = GD_HEADER_BAR (widget);
1169
GdHeaderBarPrivate *priv = bar->priv;
1171
GTK_WIDGET_CLASS (gd_header_bar_parent_class)->map (widget);
1173
if (priv->event_window)
1174
gdk_window_show_unraised (priv->event_window);
1178
gd_header_bar_unmap (GtkWidget *widget)
1180
GdHeaderBar *bar = GD_HEADER_BAR (widget);
1181
GdHeaderBarPrivate *priv = bar->priv;
1183
if (priv->event_window)
1184
gdk_window_hide (priv->event_window);
1186
GTK_WIDGET_CLASS (gd_header_bar_parent_class)->unmap (widget);
1190
gd_header_bar_draw (GtkWidget *widget,
1193
GtkStyleContext *context;
1195
context = gtk_widget_get_style_context (widget);
1197
gtk_render_background (context, cr, 0, 0,
1198
gtk_widget_get_allocated_width (widget),
1199
gtk_widget_get_allocated_height (widget));
1200
gtk_render_frame (context, cr, 0, 0,
1201
gtk_widget_get_allocated_width (widget),
1202
gtk_widget_get_allocated_height (widget));
1205
GTK_WIDGET_CLASS (gd_header_bar_parent_class)->draw (widget, cr);
1211
gd_header_bar_class_init (GdHeaderBarClass *class)
1213
GObjectClass *object_class = G_OBJECT_CLASS (class);
1214
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
1215
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
1217
object_class->get_property = gd_header_bar_get_property;
1218
object_class->set_property = gd_header_bar_set_property;
1219
object_class->finalize = gd_header_bar_finalize;
1221
widget_class->size_allocate = gd_header_bar_size_allocate;
1222
widget_class->get_preferred_width = gd_header_bar_get_preferred_width;
1223
widget_class->get_preferred_height = gd_header_bar_get_preferred_height;
1224
widget_class->get_preferred_height_for_width = gd_header_bar_get_preferred_height_for_width;
1225
widget_class->get_preferred_width_for_height = gd_header_bar_get_preferred_width_for_height;
1226
widget_class->button_press_event = gd_header_bar_button_press;
1227
widget_class->realize = gd_header_bar_realize;
1228
widget_class->unrealize = gd_header_bar_unrealize;
1229
widget_class->map = gd_header_bar_map;
1230
widget_class->unmap = gd_header_bar_unmap;
1231
widget_class->draw = gd_header_bar_draw;
1233
container_class->add = gd_header_bar_add;
1234
container_class->remove = gd_header_bar_remove;
1235
container_class->forall = gd_header_bar_forall;
1236
container_class->child_type = gd_header_bar_child_type;
1237
container_class->set_child_property = gd_header_bar_set_child_property;
1238
container_class->get_child_property = gd_header_bar_get_child_property;
1239
gtk_container_class_handle_border_width (container_class);
1241
gtk_container_class_install_child_property (container_class,
1242
CHILD_PROP_PACK_TYPE,
1243
g_param_spec_enum ("pack-type",
1245
"A GtkPackType indicating whether the child is packed with reference to the start or end of the parent",
1246
GTK_TYPE_PACK_TYPE, GTK_PACK_START,
1247
G_PARAM_READWRITE));
1248
gtk_container_class_install_child_property (container_class,
1249
CHILD_PROP_POSITION,
1250
g_param_spec_int ("position",
1252
"The index of the child in the parent",
1256
g_object_class_install_property (object_class,
1258
g_param_spec_string ("title",
1260
"The title to display",
1262
G_PARAM_READWRITE));
1264
g_object_class_install_property (object_class,
1266
g_param_spec_string ("subtitle",
1268
"The subtitle to display",
1270
G_PARAM_READWRITE));
1272
g_object_class_install_property (object_class,
1274
g_param_spec_object ("custom-title",
1276
"Custom title widget to display",
1280
G_PARAM_STATIC_STRINGS));
1282
g_object_class_install_property (object_class,
1284
g_param_spec_int ("spacing",
1286
"The amount of space between children",
1289
G_PARAM_READWRITE));
1291
g_object_class_install_property (object_class,
1293
g_param_spec_int ("hpadding",
1294
"Horizontal padding",
1295
"The amount of space to the left and right of children",
1298
G_PARAM_READWRITE));
1300
g_object_class_install_property (object_class,
1302
g_param_spec_int ("vpadding",
1304
"The amount of space to the above and below children",
1307
G_PARAM_READWRITE));
1309
g_type_class_add_private (object_class, sizeof (GdHeaderBarPrivate));
1313
gd_header_buildable_add_child (GtkBuildable *buildable,
1314
GtkBuilder *builder,
1318
if (type && strcmp (type, "title") == 0)
1319
gd_header_bar_set_custom_title (GD_HEADER_BAR (buildable), GTK_WIDGET (child));
1321
gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
1323
GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GD_HEADER_BAR (buildable), type);
1327
gd_header_buildable_init (GtkBuildableIface *iface)
1329
iface->add_child = gd_header_buildable_add_child;
1333
gd_header_bar_pack_start (GdHeaderBar *bar,
1336
gd_header_bar_pack (bar, child, GTK_PACK_START);
1340
gd_header_bar_pack_end (GdHeaderBar *bar,
1343
gd_header_bar_pack (bar, child, GTK_PACK_END);
1347
gd_header_bar_new (void)
1349
return GTK_WIDGET (g_object_new (GD_TYPE_HEADER_BAR, NULL));