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
118struct _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
139typedef struct _GtkHeaderBarClass GtkHeaderBarClass;
140
141struct _GtkHeaderBarClass
142{
143 GtkWidgetClass parent_class;
144};
145
146enum {
147 PROP_0,
148 PROP_TITLE_WIDGET,
149 PROP_SHOW_TITLE_BUTTONS,
150 PROP_DECORATION_LAYOUT,
151 LAST_PROP
152};
153
154static GParamSpec *header_bar_props[LAST_PROP] = { NULL, };
155
156static void gtk_header_bar_buildable_init (GtkBuildableIface *iface);
157
158G_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
162static void
163create_window_controls (GtkHeaderBar *bar)
164{
165 GtkWidget *controls;
166
167 controls = gtk_window_controls_new (side: GTK_PACK_START);
168 g_object_bind_property (source: bar, source_property: "decoration-layout",
169 target: controls, target_property: "decoration-layout",
170 flags: G_BINDING_SYNC_CREATE);
171 g_object_bind_property (source: controls, source_property: "empty",
172 target: controls, target_property: "visible",
173 flags: G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
174 gtk_box_prepend (GTK_BOX (bar->start_box), child: controls);
175 bar->start_window_controls = controls;
176
177 controls = gtk_window_controls_new (side: GTK_PACK_END);
178 g_object_bind_property (source: bar, source_property: "decoration-layout",
179 target: controls, target_property: "decoration-layout",
180 flags: G_BINDING_SYNC_CREATE);
181 g_object_bind_property (source: controls, source_property: "empty",
182 target: controls, target_property: "visible",
183 flags: G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
184 gtk_box_append (GTK_BOX (bar->end_box), child: controls);
185 bar->end_window_controls = controls;
186}
187
188static void
189update_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 (widget: bar->start_box);
203 w != NULL;
204 w = _gtk_widget_get_next_sibling (widget: 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 (widget: bar->end_box);
215 w != NULL;
216 w = _gtk_widget_get_next_sibling (widget: 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), css_class: "default-decoration");
228 else
229 gtk_widget_add_css_class (GTK_WIDGET (bar), css_class: "default-decoration");
230}
231
232void
233_gtk_header_bar_track_default_decoration (GtkHeaderBar *bar)
234{
235 bar->track_default_decoration = TRUE;
236
237 update_default_decoration (bar);
238}
239
240static void
241update_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), str: title);
261}
262
263static void
264construct_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 (widget: label, css_class: "title");
272 gtk_widget_set_valign (widget: label, align: 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), mode: 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), child: 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 */
301void
302gtk_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), child: 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), pspec: 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 */
343GtkWidget *
344gtk_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
351static void
352gtk_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
367static void
368gtk_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
376static void
377gtk_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
391static void
392gtk_header_bar_finalize (GObject *object)
393{
394 GtkHeaderBar *bar = GTK_HEADER_BAR (object);
395
396 g_free (mem: bar->decoration_layout);
397
398 G_OBJECT_CLASS (gtk_header_bar_parent_class)->finalize (object);
399}
400
401static void
402gtk_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, v_object: bar->title_widget);
413 break;
414
415 case PROP_SHOW_TITLE_BUTTONS:
416 g_value_set_boolean (value, v_boolean: gtk_header_bar_get_show_title_buttons (bar));
417 break;
418
419 case PROP_DECORATION_LAYOUT:
420 g_value_set_string (value, v_string: 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
429static void
430gtk_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, title_widget: g_value_get_object (value));
441 break;
442
443 case PROP_SHOW_TITLE_BUTTONS:
444 gtk_header_bar_set_show_title_buttons (bar, setting: g_value_get_boolean (value));
445 break;
446
447 case PROP_DECORATION_LAYOUT:
448 gtk_header_bar_set_decoration_layout (bar, layout: 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
457static void
458gtk_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), child: widget);
467 }
468 else if (pack_type == GTK_PACK_END)
469 {
470 gtk_box_prepend (GTK_BOX (bar->end_box), child: widget);
471 }
472
473 if (bar->track_default_decoration)
474 update_default_decoration (bar);
475}
476
477/**
478 * gtk_header_bar_remove:
479 * @bar: a `GtkHeaderBar`
480 * @child: the child to remove
481 *
482 * Removes a child from the `GtkHeaderBar`.
483 *
484 * The child must have been added with
485 * [method@Gtk.HeaderBar.pack_start],
486 * [method@Gtk.HeaderBar.pack_end] or
487 * [method@Gtk.HeaderBar.set_title_widget].
488 */
489void
490gtk_header_bar_remove (GtkHeaderBar *bar,
491 GtkWidget *child)
492{
493 GtkWidget *parent;
494 gboolean removed = FALSE;
495
496 parent = gtk_widget_get_parent (widget: child);
497
498 if (parent == bar->start_box)
499 {
500 gtk_box_remove (GTK_BOX (bar->start_box), child);
501 removed = TRUE;
502 }
503 else if (parent == bar->end_box)
504 {
505 gtk_box_remove (GTK_BOX (bar->end_box), child);
506 removed = TRUE;
507 }
508 else if (parent == bar->center_box)
509 {
510 gtk_center_box_set_center_widget (GTK_CENTER_BOX (bar->center_box), NULL);
511 removed = TRUE;
512 }
513
514 if (removed && bar->track_default_decoration)
515 update_default_decoration (bar);
516}
517
518static GtkSizeRequestMode
519gtk_header_bar_get_request_mode (GtkWidget *widget)
520{
521 GtkWidget *w;
522 int wfh = 0, hfw = 0;
523
524 for (w = gtk_widget_get_first_child (widget);
525 w != NULL;
526 w = gtk_widget_get_next_sibling (widget: w))
527 {
528 GtkSizeRequestMode mode = gtk_widget_get_request_mode (widget: w);
529
530 switch (mode)
531 {
532 case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
533 hfw ++;
534 break;
535 case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
536 wfh ++;
537 break;
538 case GTK_SIZE_REQUEST_CONSTANT_SIZE:
539 default:
540 break;
541 }
542 }
543
544 if (hfw == 0 && wfh == 0)
545 return GTK_SIZE_REQUEST_CONSTANT_SIZE;
546 else
547 return wfh > hfw ?
548 GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
549 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
550}
551
552static void
553gtk_header_bar_class_init (GtkHeaderBarClass *class)
554{
555 GObjectClass *object_class = G_OBJECT_CLASS (class);
556 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
557
558 object_class->dispose = gtk_header_bar_dispose;
559 object_class->finalize = gtk_header_bar_finalize;
560 object_class->get_property = gtk_header_bar_get_property;
561 object_class->set_property = gtk_header_bar_set_property;
562
563 widget_class->root = gtk_header_bar_root;
564 widget_class->unroot = gtk_header_bar_unroot;
565 widget_class->get_request_mode = gtk_header_bar_get_request_mode;
566
567 header_bar_props[PROP_TITLE_WIDGET] =
568 g_param_spec_object (name: "title-widget",
569 P_("Title Widget"),
570 P_("Title widget to display"),
571 GTK_TYPE_WIDGET,
572 flags: G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
573
574 /**
575 * 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)
576 *
577 * Whether to show title buttons like close, minimize, maximize.
578 *
579 * Which buttons are actually shown and where is determined
580 * by the [property@Gtk.HeaderBar:decoration-layout] property,
581 * and by the state of the window (e.g. a close button will not
582 * be shown if the window can't be closed).
583 */
584 header_bar_props[PROP_SHOW_TITLE_BUTTONS] =
585 g_param_spec_boolean (name: "show-title-buttons",
586 P_("Show title buttons"),
587 P_("Whether to show title buttons"),
588 TRUE,
589 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
590
591 /**
592 * GtkHeaderBar:decoration-layout: (attributes org.gtk.Property.get=gtk_header_bar_get_decoration_layout org.gtk.Property.set=gtk_header_bar_set_decoration_layout)
593 *
594 * The decoration layout for buttons.
595 *
596 * If this property is not set, the
597 * [property@Gtk.Settings:gtk-decoration-layout] setting is used.
598 */
599 header_bar_props[PROP_DECORATION_LAYOUT] =
600 g_param_spec_string (name: "decoration-layout",
601 P_("Decoration Layout"),
602 P_("The layout for window decorations"),
603 NULL,
604 GTK_PARAM_READWRITE);
605
606 g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs: header_bar_props);
607
608 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
609 gtk_widget_class_set_css_name (widget_class, I_("headerbar"));
610 gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_GROUP);
611}
612
613static void
614gtk_header_bar_init (GtkHeaderBar *bar)
615{
616 bar->title_widget = NULL;
617 bar->decoration_layout = NULL;
618 bar->show_title_buttons = TRUE;
619
620 bar->handle = gtk_window_handle_new ();
621 gtk_widget_set_parent (widget: bar->handle, GTK_WIDGET (bar));
622
623 bar->center_box = gtk_center_box_new ();
624 gtk_window_handle_set_child (self: GTK_WINDOW_HANDLE (ptr: bar->handle), child: bar->center_box);
625
626 bar->start_box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
627 gtk_widget_add_css_class (widget: bar->start_box, css_class: "start");
628 gtk_center_box_set_start_widget (GTK_CENTER_BOX (bar->center_box), child: bar->start_box);
629
630 bar->end_box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
631 gtk_widget_add_css_class (widget: bar->end_box, css_class: "end");
632 gtk_center_box_set_end_widget (GTK_CENTER_BOX (bar->center_box), child: bar->end_box);
633
634 construct_title_label (bar);
635 create_window_controls (bar);
636}
637
638static GtkBuildableIface *parent_buildable_iface;
639
640static void
641gtk_header_bar_buildable_add_child (GtkBuildable *buildable,
642 GtkBuilder *builder,
643 GObject *child,
644 const char *type)
645{
646 if (g_strcmp0 (str1: type, str2: "title") == 0)
647 gtk_header_bar_set_title_widget (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
648 else if (g_strcmp0 (str1: type, str2: "start") == 0)
649 gtk_header_bar_pack_start (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
650 else if (g_strcmp0 (str1: type, str2: "end") == 0)
651 gtk_header_bar_pack_end (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
652 else if (type == NULL && GTK_IS_WIDGET (child))
653 gtk_header_bar_pack_start (GTK_HEADER_BAR (buildable), GTK_WIDGET (child));
654 else
655 parent_buildable_iface->add_child (buildable, builder, child, type);
656}
657
658static void
659gtk_header_bar_buildable_init (GtkBuildableIface *iface)
660{
661 parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface);
662
663 iface->add_child = gtk_header_bar_buildable_add_child;
664}
665
666/**
667 * gtk_header_bar_pack_start:
668 * @bar: A `GtkHeaderBar`
669 * @child: the `GtkWidget` to be added to @bar
670 *
671 * Adds @child to @bar, packed with reference to the
672 * start of the @bar.
673 */
674void
675gtk_header_bar_pack_start (GtkHeaderBar *bar,
676 GtkWidget *child)
677{
678 gtk_header_bar_pack (bar, widget: child, pack_type: GTK_PACK_START);
679}
680
681/**
682 * gtk_header_bar_pack_end:
683 * @bar: A `GtkHeaderBar`
684 * @child: the `GtkWidget` to be added to @bar
685 *
686 * Adds @child to @bar, packed with reference to the
687 * end of the @bar.
688 */
689void
690gtk_header_bar_pack_end (GtkHeaderBar *bar,
691 GtkWidget *child)
692{
693 gtk_header_bar_pack (bar, widget: child, pack_type: GTK_PACK_END);
694}
695
696/**
697 * gtk_header_bar_new:
698 *
699 * Creates a new `GtkHeaderBar` widget.
700 *
701 * Returns: a new `GtkHeaderBar`
702 */
703GtkWidget *
704gtk_header_bar_new (void)
705{
706 return GTK_WIDGET (g_object_new (GTK_TYPE_HEADER_BAR, NULL));
707}
708
709/**
710 * gtk_header_bar_get_show_title_buttons: (attributes org.gtk.Method.get_property=show-title-buttons)
711 * @bar: a `GtkHeaderBar`
712 *
713 * Returns whether this header bar shows the standard window
714 * title buttons.
715 *
716 * Returns: %TRUE if title buttons are shown
717 */
718gboolean
719gtk_header_bar_get_show_title_buttons (GtkHeaderBar *bar)
720{
721 g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), FALSE);
722
723 return bar->show_title_buttons;
724}
725
726/**
727 * gtk_header_bar_set_show_title_buttons: (attributes org.gtk.Method.set_property=show-title-buttons)
728 * @bar: a `GtkHeaderBar`
729 * @setting: %TRUE to show standard title buttons
730 *
731 * Sets whether this header bar shows the standard window
732 * title buttons.
733 */
734void
735gtk_header_bar_set_show_title_buttons (GtkHeaderBar *bar,
736 gboolean setting)
737{
738 g_return_if_fail (GTK_IS_HEADER_BAR (bar));
739
740 setting = setting != FALSE;
741
742 if (bar->show_title_buttons == setting)
743 return;
744
745 bar->show_title_buttons = setting;
746
747 if (setting)
748 create_window_controls (bar);
749 else
750 {
751 if (bar->start_box && bar->start_window_controls)
752 {
753 gtk_box_remove (GTK_BOX (bar->start_box), child: bar->start_window_controls);
754 bar->start_window_controls = NULL;
755 }
756
757 if (bar->end_box && bar->end_window_controls)
758 {
759 gtk_box_remove (GTK_BOX (bar->end_box), child: bar->end_window_controls);
760 bar->end_window_controls = NULL;
761 }
762 }
763
764 g_object_notify_by_pspec (G_OBJECT (bar), pspec: header_bar_props[PROP_SHOW_TITLE_BUTTONS]);
765}
766
767/**
768 * gtk_header_bar_set_decoration_layout: (attributes org.gtk.Method.set_property=decoration-layout)
769 * @bar: a `GtkHeaderBar`
770 * @layout: (nullable): a decoration layout, or %NULL to unset the layout
771 *
772 * Sets the decoration layout for this header bar.
773 *
774 * This property overrides the
775 * [property@Gtk.Settings:gtk-decoration-layout] setting.
776 *
777 * There can be valid reasons for overriding the setting, such
778 * as a header bar design that does not allow for buttons to take
779 * room on the right, or only offers room for a single close button.
780 * Split header bars are another example for overriding the setting.
781 *
782 * The format of the string is button names, separated by commas.
783 * A colon separates the buttons that should appear on the left
784 * from those on the right. Recognized button names are minimize,
785 * maximize, close and icon (the window icon).
786 *
787 * For example, “icon:minimize,maximize,close” specifies a icon
788 * on the left, and minimize, maximize and close buttons on the right.
789 */
790void
791gtk_header_bar_set_decoration_layout (GtkHeaderBar *bar,
792 const char *layout)
793{
794 g_return_if_fail (GTK_IS_HEADER_BAR (bar));
795
796 g_free (mem: bar->decoration_layout);
797 bar->decoration_layout = g_strdup (str: layout);
798
799 g_object_notify_by_pspec (G_OBJECT (bar), pspec: header_bar_props[PROP_DECORATION_LAYOUT]);
800}
801
802/**
803 * gtk_header_bar_get_decoration_layout: (attributes org.gtk.Method.get_property=decoration-layout)
804 * @bar: a `GtkHeaderBar`
805 *
806 * Gets the decoration layout of the `GtkHeaderBar`.
807 *
808 * Returns: (nullable): the decoration layout
809 */
810const char *
811gtk_header_bar_get_decoration_layout (GtkHeaderBar *bar)
812{
813 g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), NULL);
814
815 return bar->decoration_layout;
816}
817

source code of gtk/gtk/gtkheaderbar.c