[gtk/wip/exalm/titlebuttons: 2/2] headerbar: Use GtkTitleButtons
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/exalm/titlebuttons: 2/2] headerbar: Use GtkTitleButtons
- Date: Fri, 24 Apr 2020 16:54:30 +0000 (UTC)
commit 8a03bdd859954452be07cd532a78cdf8690ae641
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Fri Apr 24 20:55:43 2020 +0500
headerbar: Use GtkTitleButtons
Now that the title buttons are encapsulated in a separate widget, use
it in the header bar.
Hide them when empty, so that they don't add extra spacing.
gtk/gtkheaderbar.c | 354 +++++++----------------------------------------------
1 file changed, 45 insertions(+), 309 deletions(-)
---
diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c
index 4afaa7dc19..f10d1d75c9 100644
--- a/gtk/gtkheaderbar.c
+++ b/gtk/gtkheaderbar.c
@@ -21,20 +21,17 @@
#include "gtkheaderbarprivate.h"
-#include "gtkactionable.h"
#include "gtkbox.h"
-#include "gtkbutton.h"
#include "gtkbuildable.h"
#include "gtkcenterlayout.h"
#include "gtkcssnodeprivate.h"
-#include "gtkimage.h"
#include "gtkintl.h"
#include "gtklabel.h"
#include "gtkprivate.h"
#include "gtksizerequest.h"
+#include "gtktitlebuttons.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
-#include "gtkwindowprivate.h"
#include "gtknative.h"
#include "a11y/gtkcontaineraccessible.h"
@@ -68,21 +65,18 @@
* |[<!-- language="plain" -->
* headerbar
* ├── box.start
- * │ ╰── box
- * │ ├── [image.titlebutton.icon]
- * │ ├── [button.titlebutton.minimize]
- * │ ├── [button.titlebutton.maximize]
- * │ ╰── [button.titlebutton.close]
+ * │ ╰── titlebuttons.start
* ├── [Custom Title]
* ╰── box.end
+ * │ ╰── titlebuttons.end
* ]|
*
- * A #GtkHeaderBar's CSS node is called headerbar. It contains two box subnodes at the start
- * and end of the headerbar, as well as a center node that represents the title.
+ * A #GtkHeaderBar's CSS node is called headerbar. It contains two box subnodes
+ * at the start and end of the headerbar, as well as a center node that
+ * represents the title.
*
- * The titlebuttons get their own box subnode, either in the start box or in the end box.
- * Which of the title buttons exist and where they are placed exactly depends on the
- * desktop environment.
+ * Each of the boxes contains a titlebuttons subnode, see #GtkTitleButtons for
+ * details.
*/
#define MIN_TITLE_CHARS 5
@@ -119,8 +113,8 @@ struct _GtkHeaderBarPrivate
gchar *decoration_layout;
gboolean track_default_decoration;
- GtkWidget *titlebar_start_box;
- GtkWidget *titlebar_end_box;
+ GtkWidget *start_title_buttons;
+ GtkWidget *end_title_buttons;
GdkSurfaceState state;
};
@@ -214,204 +208,31 @@ create_title_box (const char *title,
return label_box;
}
-static gboolean
-update_window_icon (GtkHeaderBar *bar,
- GtkWindow *window,
- GtkWidget *icon)
-{
- GdkPaintable *paintable;
- gint scale;
-
- scale = gtk_widget_get_scale_factor (icon);
- paintable = gtk_window_get_icon_for_size (window, 20 * scale);
-
- if (paintable)
- {
- gtk_image_set_from_paintable (GTK_IMAGE (icon), paintable);
- g_object_unref (paintable);
- gtk_widget_show (icon);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
static void
-update_window_buttons (GtkHeaderBar *bar)
+create_title_buttons (GtkHeaderBar *bar)
{
GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
- GtkWidget *widget = GTK_WIDGET (bar);
- GtkWidget *toplevel;
- GtkWindow *window;
- gchar *layout_desc;
- gchar **tokens, **t;
- gint i, j;
- gboolean is_sovereign_window;
-
- if (!gtk_widget_get_realized (widget))
- return;
-
- toplevel = GTK_WIDGET (gtk_widget_get_root (widget));
- if (!GTK_IS_WINDOW (toplevel))
- return;
-
- if (priv->titlebar_start_box)
- {
- gtk_widget_unparent (priv->titlebar_start_box);
- priv->titlebar_start_box = NULL;
- }
- if (priv->titlebar_end_box)
- {
- gtk_widget_unparent (priv->titlebar_end_box);
- priv->titlebar_end_box = NULL;
- }
-
- if (!priv->show_title_buttons)
- return;
-
- if (priv->decoration_layout)
- layout_desc = g_strdup (priv->decoration_layout);
- else
- g_object_get (gtk_widget_get_settings (widget),
- "gtk-decoration-layout", &layout_desc,
- NULL);
-
- window = GTK_WINDOW (toplevel);
-
- is_sovereign_window = !gtk_window_get_modal (window) &&
- gtk_window_get_transient_for (window) == NULL;
-
- tokens = g_strsplit (layout_desc, ":", 2);
- if (tokens)
- {
- for (i = 0; i < 2; i++)
- {
- GtkWidget *box;
- int n_children = 0;
-
- if (tokens[i] == NULL)
- break;
-
- t = g_strsplit (tokens[i], ",", -1);
-
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-
- for (j = 0; t[j]; j++)
- {
- GtkWidget *button = NULL;
- GtkWidget *image = NULL;
- AtkObject *accessible;
-
- if (strcmp (t[j], "icon") == 0 &&
- is_sovereign_window)
- {
- button = gtk_image_new ();
- gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
- gtk_widget_add_css_class (button, "titlebutton");
- gtk_widget_add_css_class (button, "icon");
-
- if (!update_window_icon (bar, window, button))
- {
- g_object_ref_sink (button);
- g_object_unref (button);
- button = NULL;
- }
- }
- else if (strcmp (t[j], "minimize") == 0 &&
- is_sovereign_window)
- {
- button = gtk_button_new ();
- gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
- gtk_widget_add_css_class (button, "titlebutton");
- gtk_widget_add_css_class (button, "minimize");
- image = gtk_image_new_from_icon_name ("window-minimize-symbolic");
- g_object_set (image, "use-fallback", TRUE, NULL);
- gtk_container_add (GTK_CONTAINER (button), image);
- gtk_widget_set_can_focus (button, FALSE);
- gtk_actionable_set_action_name (GTK_ACTIONABLE (button),
- "window.minimize");
-
- accessible = gtk_widget_get_accessible (button);
- if (GTK_IS_ACCESSIBLE (accessible))
- atk_object_set_name (accessible, _("Minimize"));
- }
- else if (strcmp (t[j], "maximize") == 0 &&
- gtk_window_get_resizable (window) &&
- is_sovereign_window)
- {
- const gchar *icon_name;
- gboolean maximized = gtk_window_is_maximized (window);
-
- icon_name = maximized ? "window-restore-symbolic" : "window-maximize-symbolic";
- button = gtk_button_new ();
- gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
- gtk_widget_add_css_class (button, "titlebutton");
- gtk_widget_add_css_class (button, "maximize");
- image = gtk_image_new_from_icon_name (icon_name);
- g_object_set (image, "use-fallback", TRUE, NULL);
- gtk_container_add (GTK_CONTAINER (button), image);
- gtk_widget_set_can_focus (button, FALSE);
- gtk_actionable_set_action_name (GTK_ACTIONABLE (button),
- "window.toggle-maximized");
-
- accessible = gtk_widget_get_accessible (button);
- if (GTK_IS_ACCESSIBLE (accessible))
- atk_object_set_name (accessible, maximized ? _("Restore") : _("Maximize"));
- }
- else if (strcmp (t[j], "close") == 0 &&
- gtk_window_get_deletable (window))
- {
- button = gtk_button_new ();
- gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
- image = gtk_image_new_from_icon_name ("window-close-symbolic");
- gtk_widget_add_css_class (button, "titlebutton");
- gtk_widget_add_css_class (button, "close");
- g_object_set (image, "use-fallback", TRUE, NULL);
- gtk_container_add (GTK_CONTAINER (button), image);
- gtk_widget_set_can_focus (button, FALSE);
- gtk_actionable_set_action_name (GTK_ACTIONABLE (button),
- "window.close");
-
- accessible = gtk_widget_get_accessible (button);
- if (GTK_IS_ACCESSIBLE (accessible))
- atk_object_set_name (accessible, _("Close"));
- }
-
- if (button)
- {
- gtk_container_add (GTK_CONTAINER (box), button);
- n_children ++;
- }
- }
- g_strfreev (t);
-
- if (n_children == 0)
- {
- g_object_ref_sink (box);
- g_object_unref (box);
- continue;
- }
-
- if (i == 0)
- gtk_widget_add_css_class (box, GTK_STYLE_CLASS_LEFT);
- else
- gtk_widget_add_css_class (box, GTK_STYLE_CLASS_RIGHT);
-
- if (i == 0)
- {
- priv->titlebar_start_box = box;
- gtk_container_add (GTK_CONTAINER (priv->start_box), box);
- }
- else
- {
- priv->titlebar_end_box = box;
- gtk_container_add (GTK_CONTAINER (priv->end_box), box);
- }
- }
- g_strfreev (tokens);
- }
- g_free (layout_desc);
+ GtkWidget *buttons;
+
+ buttons = gtk_title_buttons_new (GTK_PACK_START);
+ g_object_bind_property (bar, "decoration-layout",
+ buttons, "decoration-layout",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (buttons, "empty",
+ buttons, "visible",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+ gtk_container_add (GTK_CONTAINER (priv->start_box), buttons);
+ priv->start_title_buttons = buttons;
+
+ buttons = gtk_title_buttons_new (GTK_PACK_END);
+ g_object_bind_property (bar, "decoration-layout",
+ buttons, "decoration-layout",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (buttons, "empty",
+ buttons, "visible",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+ gtk_container_add (GTK_CONTAINER (priv->end_box), buttons);
+ priv->end_title_buttons = buttons;
}
static void
@@ -434,7 +255,7 @@ update_default_decoration (GtkHeaderBar *bar)
w != NULL;
w = _gtk_widget_get_next_sibling (w))
{
- if (w != priv->titlebar_start_box)
+ if (w != priv->start_title_buttons)
{
have_children = TRUE;
break;
@@ -446,7 +267,7 @@ update_default_decoration (GtkHeaderBar *bar)
w != NULL;
w = _gtk_widget_get_next_sibling (w))
{
- if (w != priv->titlebar_end_box)
+ if (w != priv->end_title_buttons)
{
have_children = TRUE;
break;
@@ -872,7 +693,7 @@ gtk_header_bar_forall (GtkContainer *container,
{
GtkWidget *next = _gtk_widget_get_next_sibling (w);
- if (w != priv->titlebar_start_box)
+ if (w != priv->start_title_buttons)
(* callback) (w, callback_data);
w = next;
@@ -889,7 +710,7 @@ gtk_header_bar_forall (GtkContainer *container,
{
GtkWidget *next = _gtk_widget_get_next_sibling (w);
- if (w != priv->titlebar_end_box)
+ if (w != priv->end_title_buttons)
(* callback) (w, callback_data);
w = next;
@@ -903,93 +724,6 @@ gtk_header_bar_child_type (GtkContainer *container)
return GTK_TYPE_WIDGET;
}
-static void surface_state_changed (GtkWidget *widget);
-
-static void window_notify_cb (GtkHeaderBar *header_bar,
- GParamSpec *pspec,
- GtkWindow *window);
-
-static void
-gtk_header_bar_realize (GtkWidget *widget)
-{
- GtkSettings *settings;
- GtkWidget *root;
-
- GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->realize (widget);
-
- settings = gtk_widget_get_settings (widget);
- g_signal_connect_swapped (settings, "notify::gtk-decoration-layout",
- G_CALLBACK (update_window_buttons), widget);
- g_signal_connect_swapped (gtk_native_get_surface (gtk_widget_get_native (widget)), "notify::state",
- G_CALLBACK (surface_state_changed), widget);
-
- root = GTK_WIDGET (gtk_widget_get_root (widget));
-
- if (GTK_IS_WINDOW (root))
- g_signal_connect_swapped (root, "notify",
- G_CALLBACK (window_notify_cb), widget);
-
- update_window_buttons (GTK_HEADER_BAR (widget));
-}
-
-static void
-gtk_header_bar_unrealize (GtkWidget *widget)
-{
- GtkSettings *settings;
-
- settings = gtk_widget_get_settings (widget);
-
- g_signal_handlers_disconnect_by_func (settings, update_window_buttons, widget);
- g_signal_handlers_disconnect_by_func (gtk_native_get_surface (gtk_widget_get_native (widget)),
surface_state_changed, widget);
- g_signal_handlers_disconnect_by_func (gtk_widget_get_root (widget), window_notify_cb, widget);
-
- GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->unrealize (widget);
-}
-
-static void
-surface_state_changed (GtkWidget *widget)
-{
- GtkHeaderBar *bar = GTK_HEADER_BAR (widget);
- GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
- GdkSurfaceState changed, new_state;
-
- new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (gtk_widget_get_native
(widget))));
- changed = new_state ^ priv->state;
- priv->state = new_state;
-
- if (changed & (GDK_SURFACE_STATE_FULLSCREEN |
- GDK_SURFACE_STATE_MAXIMIZED |
- GDK_SURFACE_STATE_TILED |
- GDK_SURFACE_STATE_TOP_TILED |
- GDK_SURFACE_STATE_RIGHT_TILED |
- GDK_SURFACE_STATE_BOTTOM_TILED |
- GDK_SURFACE_STATE_LEFT_TILED))
- update_window_buttons (bar);
-}
-
-static void
-window_notify_cb (GtkHeaderBar *header_bar,
- GParamSpec *pspec,
- GtkWindow *window)
-{
- if (pspec->name == I_("deletable") ||
- pspec->name == I_("icon-name") ||
- pspec->name == I_("modal") ||
- pspec->name == I_("resizable") ||
- pspec->name == I_("transient-for"))
- update_window_buttons (header_bar);
-}
-
-static void
-gtk_header_bar_root (GtkWidget *widget)
-{
- GtkHeaderBar *bar = GTK_HEADER_BAR (widget);
-
- GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->root (widget);
-
- update_window_buttons (bar);
-}
-
static void
gtk_header_bar_class_init (GtkHeaderBarClass *class)
{
@@ -1002,10 +736,6 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
object_class->get_property = gtk_header_bar_get_property;
object_class->set_property = gtk_header_bar_set_property;
- widget_class->realize = gtk_header_bar_realize;
- widget_class->unrealize = gtk_header_bar_unrealize;
- widget_class->root = gtk_header_bar_root;
-
container_class->add = gtk_header_bar_add;
container_class->remove = gtk_header_bar_remove;
container_class->forall = gtk_header_bar_forall;
@@ -1227,7 +957,15 @@ gtk_header_bar_set_show_title_buttons (GtkHeaderBar *bar,
return;
priv->show_title_buttons = setting;
- update_window_buttons (bar);
+
+ if (setting)
+ create_title_buttons (bar);
+ else
+ {
+ g_clear_pointer (&priv->start_title_buttons, gtk_widget_unparent);
+ g_clear_pointer (&priv->end_title_buttons, gtk_widget_unparent);
+ }
+
g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_SHOW_TITLE_BUTTONS]);
}
@@ -1320,8 +1058,6 @@ gtk_header_bar_set_decoration_layout (GtkHeaderBar *bar,
g_free (priv->decoration_layout);
priv->decoration_layout = g_strdup (layout);
- update_window_buttons (bar);
-
g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_DECORATION_LAYOUT]);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]