1 /*
2 * Copyright (c) 2013 Red Hat, Inc.
3 *
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.
8 *
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.
13 *
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
17 *
18 */
19
20 #include "config.h"
21
22 #include "gtkheaderbarprivate.h"
23
24 #include "gtkbinlayout.h"
25 #include "gtkbox.h"
26 #include "gtkbuildable.h"
27 #include "gtkcenterbox.h"
28 #include "gtkintl.h"
29 #include "gtklabel.h"
30 #include "gtknative.h"
31 #include "gtkprivate.h"
32 #include "gtksizerequest.h"
33 #include "gtktypebuiltins.h"
34 #include "gtkwidgetprivate.h"
35 #include "gtkwindowcontrols.h"
36 #include "gtkwindowhandle.h"
37
38 #include <string.h>
39
40 /**
41 * GtkHeaderBar:
42 *
43 * `GtkHeaderBar` is a widget for creating custom title bars for windows.
44 *
45 * ![An example GtkHeaderBar](headerbar.png)
46 *
47 * `GtkHeaderBar` is similar to a horizontal `GtkCenterBox`. It allows
48 * children to be placed at the start or the end. In addition, it allows
49 * the window title to be displayed. The title will be centered with respect
50 * to the width of the box, even if the children at either side take up
51 * different amounts of space.
52 *
53 * `GtkHeaderBar` can add typical window frame controls, such as minimize,
54 * maximize and close buttons, or the window icon.
55 *
56 * For these reasons, `GtkHeaderBar` is the natural choice for use as the
57 * custom titlebar widget of a `GtkWindow (see [method@Gtk.Window.set_titlebar]),
58 * as it gives features typical of titlebars while allowing the addition of
59 * child widgets.
60 *
61 * ## GtkHeaderBar as GtkBuildable
62 *
63 * The `GtkHeaderBar` implementation of the `GtkBuildable` interface supports
64 * adding children at the start or end sides by specifying “start” or “end” as
65 * the “type” attribute of a <child> element, or setting the title widget by
66 * specifying “title” value.
67 *
68 * By default the `GtkHeaderBar` uses a `GtkLabel` displaying the title of the
69 * window it is contained in as the title widget, equivalent to the following
70 * UI definition:
71 *
72 * ```xml
73 * <object class="GtkHeaderBar">
74 * <property name="title-widget">
75 * <object class="GtkLabel">
76 * <property name="label" translatable="yes">Label</property>
77 * <property name="single-line-mode">True</property>
78 * <property name="ellipsize">end</property>
79 * <property name="width-chars">5</property>
80 * <style>
81 * <class name="title"/>
82 * </style>
83 * </object>
84 * </property>
85 * </object>
86 * ```
87 *
88 * # CSS nodes
89 *
90 * ```
91 * headerbar
92 * ╰── windowhandle
93 * ╰── box
94 * ├── box.start
95 * │ ├── windowcontrols.start
96 * │ ╰── [other children]
97 * ├── [Title Widget]
98 * ╰── box.end
99 * ├── [other children]
100 * ╰── windowcontrols.end
101 * ```
102 *
103 * A `GtkHeaderBar`'s CSS node is called `headerbar`. It contains a `windowhandle`
104 * subnode, which contains a `box` subnode, which contains two `box` subnodes at
105 * the start and end of the header bar, as well as a center node that represents
106 * the title.
107 *
108 * Each of the boxes contains a `windowcontrols` subnode, see
109 * [class@Gtk.WindowControls] for details, as well as other children.
110 *
111 * # Accessibility
112 *
113 * `GtkHeaderBar` uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
114 */
115
116 #define MIN_TITLE_CHARS 5
117
118 struct _GtkHeaderBar
119 {
120 GtkWidget container;
121
122 GtkWidget *handle;
123 GtkWidget *center_box;
124 GtkWidget *start_box;
125 GtkWidget *end_box;
126
127 GtkWidget *title_label;
128 GtkWidget *title_widget;
129
130 GtkWidget *start_window_controls;
131 GtkWidget *end_window_controls;
132
133 char *decoration_layout;
134
135 guint show_title_buttons : 1;
136 guint track_default_decoration : 1;
137 };
138
139 typedef struct _GtkHeaderBarClass GtkHeaderBarClass;
140
141 struct _GtkHeaderBarClass
142 {
143 GtkWidgetClass parent_class;
144 };
145
146 enum {
147 PROP_0,
148 PROP_TITLE_WIDGET,
149 PROP_SHOW_TITLE_BUTTONS,
150 PROP_DECORATION_LAYOUT,
151 LAST_PROP
152 };
153
154 static GParamSpec *header_bar_props[LAST_PROP] = { NULL, };
155
156 static void gtk_header_bar_buildable_init (GtkBuildableIface *iface);
157
158 G_DEFINE_TYPE_WITH_CODE (GtkHeaderBar, gtk_header_bar, GTK_TYPE_WIDGET,
159 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
160 gtk_header_bar_buildable_init));
161
162 static void
create_window_controls(GtkHeaderBar * bar)163 create_window_controls (GtkHeaderBar *bar)
164 {
165 GtkWidget *controls;
166
167 controls = gtk_window_controls_new (GTK_PACK_START);
168 g_object_bind_property (bar, "decoration-layout",
169 controls, "decoration-layout",
170 G_BINDING_SYNC_CREATE);
171 g_object_bind_property (controls, "empty",
172 controls, "visible",
173 G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
174 gtk_box_prepend (GTK_BOX (bar->start_box), controls);
175 bar->start_window_controls = controls;
176
177 controls = gtk_window_controls_new (GTK_PACK_END);
178 g_object_bind_property (bar, "decoration-layout",
179 controls, "decoration-layout",
180 G_BINDING_SYNC_CREATE);
181 g_object_bind_property (controls, "empty",
182 controls, "visible",
183 G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
184 gtk_box_append (GTK_BOX (bar->end_box), controls);
185 bar->end_window_controls = controls;
186 }
187
188 static void
update_default_decoration(GtkHeaderBar * bar)189 update_default_decoration (GtkHeaderBar *bar)
190 {
191 gboolean have_children = FALSE;
192
193 /* Check whether we have any child widgets that we didn't add ourselves */
194 if (gtk_center_box_get_center_widget (GTK_CENTER_BOX (bar->center_box)) != NULL)
195 {
196 have_children = TRUE;
197 }
198 else
199 {
200 GtkWidget *w;
201
202 for (w = _gtk_widget_get_first_child (bar->start_box);
203 w != NULL;
204 w = _gtk_widget_get_next_sibling (w))
205 {
206 if (w != bar->start_window_controls)
207 {
208 have_children = TRUE;
209 break;
210 }
211 }
212
213 if (!have_children)
214 for (w = _gtk_widget_get_first_child (bar->end_box);
215 w != NULL;
216 w = _gtk_widget_get_next_sibling (w))
217 {
218 if (w != bar->end_window_controls)
219 {
220 have_children = TRUE;
221 break;
222 }
223 }
224 }
225
226 if (have_children || bar->title_widget != NULL)
227 gtk_widget_remove_css_class (GTK_WIDGET (bar), "default-decoration");
228 else
229 gtk_widget_add_css_class (GTK_WIDGET (bar), "default-decoration");
230 }
231
232 void
_gtk_header_bar_track_default_decoration(GtkHeaderBar * bar)233 _gtk_header_bar_track_default_decoration (GtkHeaderBar *bar)
234 {
235 bar->track_default_decoration = TRUE;
236
237 update_default_decoration (bar);
238 }
239
240 static void
update_title(GtkHeaderBar * bar)241 update_title (GtkHeaderBar *bar)
242 {
243 GtkRoot *root;
244 const char *title = NULL;
245
246 if (!bar->title_label)
247 return;
248
249 root = gtk_widget_get_root (GTK_WIDGET (bar));
250
251 if (GTK_IS_WINDOW (root))
252 title = gtk_window_get_title (GTK_WINDOW (root));
253
254 if (!title)
255 title = g_get_application_name ();
256
257 if (!title)
258 title = g_get_prgname ();
259
260 gtk_label_set_text (GTK_LABEL (bar->title_label), title);
261 }
262
263 static void
construct_title_label(GtkHeaderBar * bar)264 construct_title_label (GtkHeaderBar *bar)
265 {
266 GtkWidget *label;
267
268 g_assert (bar->title_label == NULL);
269
270 label = gtk_label_new (NULL);
271 gtk_widget_add_css_class (label, "title");
272 gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
273 gtk_label_set_wrap (GTK_LABEL (label), FALSE);
274 gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
275 gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
276 gtk_label_set_width_chars (GTK_LABEL (label), MIN_TITLE_CHARS);
277 gtk_center_box_set_center_widget (GTK_CENTER_BOX (bar->center_box), label);
278
279 bar->title_label = label;
280
281 update_title (bar);
282 }
283
284 /**
285 * gtk_header_bar_set_title_widget:
286 * @bar: a `GtkHeaderBar`
287 * @title_widget: (nullable): a widget to use for a title
288 *
289 * Sets the title for the `GtkHeaderBar`.
290 *
291 * When set to %NULL, the headerbar will display the title of
292 * the window it is contained in.
293 *
294 * The title should help a user identify the current view.
295 * To achieve the same style as the builtin title, use the
296 * “title” style class.
297 *
298 * You should set the title widget to %NULL, for the window
299 * title label to be visible again.
300 */
301 void
gtk_header_bar_set_title_widget(GtkHeaderBar * bar,GtkWidget * title_widget)302 gtk_header_bar_set_title_widget (GtkHeaderBar *bar,
303 GtkWidget *title_widget)
304 {
305 g_return_if_fail (GTK_IS_HEADER_BAR (bar));
306 if (title_widget)
307 g_return_if_fail (GTK_IS_WIDGET (title_widget));
308
309 /* No need to do anything if the title widget stays the same */
310 if (bar->title_widget == title_widget)
311 return;
312
313 gtk_center_box_set_center_widget (GTK_CENTER_BOX (bar->center_box), NULL);
314 bar->title_widget = NULL;
315
316 if (title_widget != NULL)
317 {
318 bar->title_widget = title_widget;
319
320 gtk_center_box_set_center_widget (GTK_CENTER_BOX (bar->center_box), title_widget);
321
322 bar->title_label = NULL;
323 }
324 else
325 {
326 if (bar->title_label == NULL)
327 construct_title_label (bar);
328 }
329
330 g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_TITLE_WIDGET]);
331 }
332
333 /**
334 * gtk_header_bar_get_title_widget:
335 * @bar: a `GtkHeaderBar`
336 *
337 * Retrieves the title widget of the header.
338 *
339 * See [method@Gtk.HeaderBar.set_title_widget].
340 *
341 * Returns: (nullable) (transfer none): the title widget of the header
342 */
343 GtkWidget *
gtk_header_bar_get_title_widget(GtkHeaderBar * bar)344 gtk_header_bar_get_title_widget (GtkHeaderBar *bar)
345 {
346 g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), NULL);
347
348 return bar->title_widget;
349 }
350
351 static void
gtk_header_bar_root(GtkWidget * widget)352 gtk_header_bar_root (GtkWidget *widget)
353 {
354 GtkWidget *root;
355
356 GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->root (widget);
357
358 root = GTK_WIDGET (gtk_widget_get_root (widget));
359
360 if (GTK_IS_WINDOW (root))
361 g_signal_connect_swapped (root, "notify::title",
362 G_CALLBACK (update_title), widget);
363
364 update_title (GTK_HEADER_BAR (widget));
365 }
366
367 static void
gtk_header_bar_unroot(GtkWidget * widget)368 gtk_header_bar_unroot (GtkWidget *widget)
369 {
370 g_signal_handlers_disconnect_by_func (gtk_widget_get_root (widget),
371 update_title, widget);
372
373 GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->unroot (widget);
374 }
375
376 static void
gtk_header_bar_dispose(GObject * object)377 gtk_header_bar_dispose (GObject *object)
378 {
379 GtkHeaderBar *bar = GTK_HEADER_BAR (object);
380
381 bar->title_widget = NULL;
382 bar->title_label = NULL;
383 bar->start_box = NULL;
384 bar->end_box = NULL;
385
386 g_clear_pointer (&bar->handle, gtk_widget_unparent);
387
388 G_OBJECT_CLASS (gtk_header_bar_parent_class)->dispose (object);
389 }
390
391 static void
gtk_header_bar_finalize(GObject * object)392 gtk_header_bar_finalize (GObject *object)
393 {
394 GtkHeaderBar *bar = GTK_HEADER_BAR (object);
395
396 g_free (bar->decoration_layout);
397
398 G_OBJECT_CLASS (gtk_header_bar_parent_class)->finalize (object);
399 }
400
401 static void
gtk_header_bar_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)402 gtk_header_bar_get_property (GObject *object,
403 guint prop_id,
404 GValue *value,
405 GParamSpec *pspec)
406 {
407 GtkHeaderBar *bar = GTK_HEADER_BAR (object);
408
409 switch (prop_id)
410 {
411 case PROP_TITLE_WIDGET:
412 g_value_set_object (value, bar->title_widget);
413 break;
414
415 case PROP_SHOW_TITLE_BUTTONS:
416 g_value_set_boolean (value, gtk_header_bar_get_show_title_buttons (bar));
417 break;
418
419 case PROP_DECORATION_LAYOUT:
420 g_value_set_string (value, gtk_header_bar_get_decoration_layout (bar));
421 break;
422
423 default:
424 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
425 break;
426 }
427 }
428
429 static void
gtk_header_bar_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)430 gtk_header_bar_set_property (GObject *object,
431 guint prop_id,
432 const GValue *value,
433 GParamSpec *pspec)
434 {
435 GtkHeaderBar *bar = GTK_HEADER_BAR (object);
436
437 switch (prop_id)
438 {
439 case PROP_TITLE_WIDGET:
440 gtk_header_bar_set_title_widget (bar, g_value_get_object (value));
441 break;
442
443 case PROP_SHOW_TITLE_BUTTONS:
444 gtk_header_bar_set_show_title_buttons (bar, g_value_get_boolean (value));
445 break;
446
447 case PROP_DECORATION_LAYOUT:
448 gtk_header_bar_set_decoration_layout (bar, g_value_get_string (value));
449 break;
450
451 default:
452 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
453 break;
454 }
455 }
456
457 static void
gtk_header_bar_pack(GtkHeaderBar * bar,GtkWidget * widget,GtkPackType pack_type)458 gtk_header_bar_pack (GtkHeaderBar *bar,
459 GtkWidget *widget,
460 GtkPackType pack_type)
461 {
462 g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
463
464 if (pack_type == GTK_PACK_START)
465 {
466 gtk_box_append (GTK_BOX (bar->start_box), widget);
467 }
468 else if (pack_type == GTK_PACK_END)
469 {
470 gtk_box_append (GTK_BOX (bar->end_box), widget);
471 gtk_box_reorder_child_after (GTK_BOX (bar->end_box), widget, NULL);
472 }
473
474 if (bar->track_default_decoration)
475 update_default_decoration (bar);
476 }
477
478 /**
479 * gtk_header_bar_remove:
480 * @bar: a `GtkHeaderBar`
481 * @child: the child to remove
482 *
483 * Removes a child from the `GtkHeaderBar`.
484 *
485 * The child must have been added with
486 * [method@Gtk.HeaderBar.pack_start],
487 * [method@Gtk.HeaderBar.pack_end] or
488 * [method@Gtk.HeaderBar.set_title_widget].
489 */
490 void
gtk_header_bar_remove(GtkHeaderBar * bar,GtkWidget * child)491 gtk_header_bar_remove (GtkHeaderBar *bar,
492 GtkWidget *child)
493 {
494 GtkWidget *parent;
495 gboolean removed = FALSE;
496
497 parent = gtk_widget_get_parent (child);
498
499 if (parent == bar->start_box)
500 {
501 gtk_box_remove (GTK_BOX (bar->start_box), child);
502 removed = TRUE;
503 }
504 else if (parent == bar->end_box)
505 {
506 gtk_box_remove (GTK_BOX (bar->end_box), child);
507 removed = TRUE;
508 }
509 else if (parent == bar->center_box)
510 {
511 gtk_center_box_set_center_widget (GTK_CENTER_BOX (bar->center_box), NULL);
512 removed = TRUE;
513 }
514
515 if (removed && bar->track_default_decoration)
516 update_default_decoration (bar);
517 }
518
519 static GtkSizeRequestMode
gtk_header_bar_get_request_mode(GtkWidget * widget)520 gtk_header_bar_get_request_mode (GtkWidget *widget)
521 {
522 GtkWidget *w;
523 int wfh = 0, hfw = 0;
524
525 for (w = gtk_widget_get_first_child (widget);
526 w != NULL;
527 w = gtk_widget_get_next_sibling (w))
528 {
529 GtkSizeRequestMode mode = gtk_widget_get_request_mode (w);
530
531 switch (mode)
532 {
533 case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
534 hfw ++;
535 break;
536 case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
537 wfh ++;
538 break;
539 case GTK_SIZE_REQUEST_CONSTANT_SIZE:
540 default:
541 break;
542 }
543 }
544
545 if (hfw == 0 && wfh == 0)
546 return GTK_SIZE_REQUEST_CONSTANT_SIZE;
547 else
548 return wfh > hfw ?
549 GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
550 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
551 }
552
553 static void
gtk_header_bar_class_init(GtkHeaderBarClass * class)554 gtk_header_bar_class_init (GtkHeaderBarClass *class)
555 {
556 GObjectClass *object_class = G_OBJECT_CLASS (class);
557 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
558
559 object_class->dispose = gtk_header_bar_dispose;
560 object_class->finalize = gtk_header_bar_finalize;
561 object_class->get_property = gtk_header_bar_get_property;
562 object_class->set_property = gtk_header_bar_set_property;
563
564 widget_class->root = gtk_header_bar_root;
565 widget_class->unroot = gtk_header_bar_unroot;
566 widget_class->get_request_mode = gtk_header_bar_get_request_mode;
567
568 header_bar_props[PROP_TITLE_WIDGET] =
569 g_param_spec_object ("title-widget",
570 P_("Title Widget"),
571 P_("Title widget to display"),
572 GTK_TYPE_WIDGET,
573 G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
574
575 /**
576 * GtkHeaderBar:show-title-buttons: (attributes org.gtk.Property.get=gtk_header_bar_get_show_title_buttons org.gtk.Property.set=gtk_header_bar_set_show_title_buttons)
577 *
578 * Whether to show title buttons like close, minimize, maximize.
579 *
580 * Which buttons are actually shown and where is determined
581 * by the [property@Gtk.HeaderBar:decoration-layout] property,
582 * and by the state of the window (e.g. a close button will not
583 * be shown if the window can't be closed).
584 */
585 header_bar_props[PROP_SHOW_TITLE_BUTTONS] =
586 g_param_spec_boolean ("show-title-buttons",
587 P_("Show title buttons"),
588 P_("Whether to show title buttons"),
589 TRUE,
590 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
591
592 /**
593 * GtkHeaderBar:decoration-layout: (attributes org.gtk.Property.get=gtk_header_bar_get_decoration_layout org.gtk.Property.set=gtk_header_bar_set_decoration_layout)
594 *
595 * The decoration layout for buttons.
596 *
597 * If this property is not set, the
598 * [property@Gtk.Settings:gtk-decoration-layout] setting is used.
599 */
600 header_bar_props[PROP_DECORATION_LAYOUT] =
601 g_param_spec_string ("decoration-layout",
602 P_("Decoration Layout"),
603 P_("The layout for window decorations"),
604 NULL,
605 GTK_PARAM_READWRITE);
606
607 g_object_class_install_properties (object_class, LAST_PROP, header_bar_props);
608
609 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
610 gtk_widget_class_set_css_name (widget_class, I_("headerbar"));
611 gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
612 }
613
614 static void
gtk_header_bar_init(GtkHeaderBar * bar)615 gtk_header_bar_init (GtkHeaderBar *bar)
616 {
617 bar->title_widget = NULL;
618 bar->decoration_layout = NULL;
619 bar->show_title_buttons = TRUE;
620
621 bar->handle = gtk_window_handle_new ();
622 gtk_widget_set_parent (bar->handle, GTK_WIDGET (bar));
623
624 bar->center_box = gtk_center_box_new ();
625 gtk_window_handle_set_child (GTK_WINDOW_HANDLE (bar->handle), bar->center_box);
626
627 bar->start_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
628 gtk_widget_add_css_class (bar->start_box, "start");
629 gtk_center_box_set_start_widget (GTK_CENTER_BOX (bar->center_box), bar->start_box);
630
631 bar->end_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
632 gtk_widget_add_css_class (bar->end_box, "end");
633 gtk_center_box_set_end_widget (GTK_CENTER_BOX (bar->center_box), bar->end_box);
634
635 construct_title_label (bar);
636 create_window_controls (bar);
637 }
638
639 static GtkBuildableIface *parent_buildable_iface;
640
641 static void
gtk_header_bar_buildable_add_child(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const char * type)642 gtk_header_bar_buildable_add_child (GtkBuildable *buildable,
643 GtkBuilder *builder,
644 GObject *child,
645 const char *type)
646 {
647 if (g_strcmp0 (type, "title") == 0)
648 gtk_header_bar_set_title_widget (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
649 else if (g_strcmp0 (type, "start") == 0)
650 gtk_header_bar_pack_start (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
651 else if (g_strcmp0 (type, "end") == 0)
652 gtk_header_bar_pack_end (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
653 else if (type == NULL && GTK_IS_WIDGET (child))
654 gtk_header_bar_pack_start (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
655 else
656 parent_buildable_iface->add_child (buildable, builder, child, type);
657 }
658
659 static void
gtk_header_bar_buildable_init(GtkBuildableIface * iface)660 gtk_header_bar_buildable_init (GtkBuildableIface *iface)
661 {
662 parent_buildable_iface = g_type_interface_peek_parent (iface);
663
664 iface->add_child = gtk_header_bar_buildable_add_child;
665 }
666
667 /**
668 * gtk_header_bar_pack_start:
669 * @bar: A `GtkHeaderBar`
670 * @child: the `GtkWidget` to be added to @bar
671 *
672 * Adds @child to @bar, packed with reference to the
673 * start of the @bar.
674 */
675 void
gtk_header_bar_pack_start(GtkHeaderBar * bar,GtkWidget * child)676 gtk_header_bar_pack_start (GtkHeaderBar *bar,
677 GtkWidget *child)
678 {
679 gtk_header_bar_pack (bar, child, GTK_PACK_START);
680 }
681
682 /**
683 * gtk_header_bar_pack_end:
684 * @bar: A `GtkHeaderBar`
685 * @child: the `GtkWidget` to be added to @bar
686 *
687 * Adds @child to @bar, packed with reference to the
688 * end of the @bar.
689 */
690 void
gtk_header_bar_pack_end(GtkHeaderBar * bar,GtkWidget * child)691 gtk_header_bar_pack_end (GtkHeaderBar *bar,
692 GtkWidget *child)
693 {
694 gtk_header_bar_pack (bar, child, GTK_PACK_END);
695 }
696
697 /**
698 * gtk_header_bar_new:
699 *
700 * Creates a new `GtkHeaderBar` widget.
701 *
702 * Returns: a new `GtkHeaderBar`
703 */
704 GtkWidget *
gtk_header_bar_new(void)705 gtk_header_bar_new (void)
706 {
707 return GTK_WIDGET (g_object_new (GTK_TYPE_HEADER_BAR, NULL));
708 }
709
710 /**
711 * gtk_header_bar_get_show_title_buttons: (attributes org.gtk.Method.get_property=show-title-buttons)
712 * @bar: a `GtkHeaderBar`
713 *
714 * Returns whether this header bar shows the standard window
715 * title buttons.
716 *
717 * Returns: %TRUE if title buttons are shown
718 */
719 gboolean
gtk_header_bar_get_show_title_buttons(GtkHeaderBar * bar)720 gtk_header_bar_get_show_title_buttons (GtkHeaderBar *bar)
721 {
722 g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), FALSE);
723
724 return bar->show_title_buttons;
725 }
726
727 /**
728 * gtk_header_bar_set_show_title_buttons: (attributes org.gtk.Method.set_property=show-title-buttons)
729 * @bar: a `GtkHeaderBar`
730 * @setting: %TRUE to show standard title buttons
731 *
732 * Sets whether this header bar shows the standard window
733 * title buttons.
734 */
735 void
gtk_header_bar_set_show_title_buttons(GtkHeaderBar * bar,gboolean setting)736 gtk_header_bar_set_show_title_buttons (GtkHeaderBar *bar,
737 gboolean setting)
738 {
739 g_return_if_fail (GTK_IS_HEADER_BAR (bar));
740
741 setting = setting != FALSE;
742
743 if (bar->show_title_buttons == setting)
744 return;
745
746 bar->show_title_buttons = setting;
747
748 if (setting)
749 create_window_controls (bar);
750 else
751 {
752 if (bar->start_box && bar->start_window_controls)
753 {
754 gtk_box_remove (GTK_BOX (bar->start_box), bar->start_window_controls);
755 bar->start_window_controls = NULL;
756 }
757
758 if (bar->end_box && bar->end_window_controls)
759 {
760 gtk_box_remove (GTK_BOX (bar->end_box), bar->end_window_controls);
761 bar->end_window_controls = NULL;
762 }
763 }
764
765 g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_SHOW_TITLE_BUTTONS]);
766 }
767
768 /**
769 * gtk_header_bar_set_decoration_layout: (attributes org.gtk.Method.set_property=decoration-layout)
770 * @bar: a `GtkHeaderBar`
771 * @layout: (nullable): a decoration layout, or %NULL to unset the layout
772 *
773 * Sets the decoration layout for this header bar.
774 *
775 * This property overrides the
776 * [property@Gtk.Settings:gtk-decoration-layout] setting.
777 *
778 * There can be valid reasons for overriding the setting, such
779 * as a header bar design that does not allow for buttons to take
780 * room on the right, or only offers room for a single close button.
781 * Split header bars are another example for overriding the setting.
782 *
783 * The format of the string is button names, separated by commas.
784 * A colon separates the buttons that should appear on the left
785 * from those on the right. Recognized button names are minimize,
786 * maximize, close and icon (the window icon).
787 *
788 * For example, “icon:minimize,maximize,close” specifies a icon
789 * on the left, and minimize, maximize and close buttons on the right.
790 */
791 void
gtk_header_bar_set_decoration_layout(GtkHeaderBar * bar,const char * layout)792 gtk_header_bar_set_decoration_layout (GtkHeaderBar *bar,
793 const char *layout)
794 {
795 g_return_if_fail (GTK_IS_HEADER_BAR (bar));
796
797 g_free (bar->decoration_layout);
798 bar->decoration_layout = g_strdup (layout);
799
800 g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_DECORATION_LAYOUT]);
801 }
802
803 /**
804 * gtk_header_bar_get_decoration_layout: (attributes org.gtk.Method.get_property=decoration-layout)
805 * @bar: a `GtkHeaderBar`
806 *
807 * Gets the decoration layout of the `GtkHeaderBar`.
808 *
809 * Returns: (nullable): the decoration layout
810 */
811 const char *
gtk_header_bar_get_decoration_layout(GtkHeaderBar * bar)812 gtk_header_bar_get_decoration_layout (GtkHeaderBar *bar)
813 {
814 g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), NULL);
815
816 return bar->decoration_layout;
817 }
818