Commit: patch 9.2.0669: GTK4: toolbar can be improved

1 view
Skip to first unread message

Christian Brabandt

unread,
Jun 17, 2026, 4:00:20 PM (9 hours ago) Jun 17
to vim...@googlegroups.com
patch 9.2.0669: GTK4: toolbar can be improved

Commit: https://github.com/vim/vim/commit/028314a8deced7dbb20aba569eaea7a36c47d050
Author: Foxe Chen <chen...@gmail.com>
Date: Wed Jun 17 19:53:57 2026 +0000

patch 9.2.0669: GTK4: toolbar can be improved

Problem: GTK4: toolbar can be improved
Solution: Implement gui_mch_menu_set_tip(), make the UI respect the
'toolbar' option (Foxe Chen).

closes: #20541

Signed-off-by: Foxe Chen <chen...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/Filelist b/Filelist
index 5526e539a..1f36de4d4 100644
--- a/Filelist
+++ b/Filelist
@@ -515,6 +515,8 @@ SRC_UNIX = \
src/gui_gtk4_cb.h \
src/gui_gtk4_da.c \
src/gui_gtk4_da.h \
+ src/gui_gtk4_tb.c \
+ src/gui_gtk4_tb.h \
src/gui_gtk_res.xml \
src/gui_motif.c \
src/gui_xmdlg.c \
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 244a7510f..9743dea43 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt* For Vim version 9.2. Last change: 2026 Jun 09
+*options.txt* For Vim version 9.2. Last change: 2026 Jun 17


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -9697,7 +9697,8 @@ A jump table for the options with a short description can be found at |Q_op|.
icons Toolbar buttons are shown with icons.
text Toolbar buttons shown with text.
horiz Icon and text of a toolbar button are
- horizontally arranged. {only in GTK+ 2 GUI}
+ horizontally arranged.
+ {only in GTK+ 2 and GTK 4 GUI}
tooltips Tooltips are active for toolbar buttons.
Tooltips refer to the popup help text which appears after the mouse
cursor is placed over a toolbar button for a brief moment.
diff --git a/src/Makefile b/src/Makefile
index a5f23612c..ef0cb8553 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1243,12 +1243,14 @@ GTK4_SRC = gui.c gui_gtk4.c gui_gtk4_f.c \
gui_gtk4_cb.c \
gui_gtk4_da.c \
gui_beval.o \
+ gui_gtk4_tb.c \
$(GRESOURCE_SRC)
GTK4_OBJ = objects/gui.o objects/gui_gtk4.o \
objects/gui_gtk4_f.o \
objects/gui_gtk4_cb.o \
objects/gui_gtk4_da.o \
objects/gui_beval.o \
+ objects/gui_gtk4_tb.o \
$(GRESOURCE_OBJ)
GTK4_DEFS = -DFEAT_GUI_GTK $(NARROW_PROTO)
GTK4_IPATH = $(GUI_INC_LOC)
@@ -1318,7 +1320,7 @@ HAIKUGUI_TESTTARGET = gui
HAIKUGUI_BUNDLE =

# All GUI files
-ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_gtk4.c gui_gtk4_f.c gui_gtk4_cb.c gui_gtk4_da.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_gtk_x11.c gui_x11.c gui_haiku.cc
+ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_gtk4.c gui_gtk4_f.c gui_gtk4_cb.c gui_gtk4_da.c gui_gtk4_tb.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_gtk_x11.c gui_x11.c gui_haiku.cc
ALL_GUI_PRO = proto/gui.pro proto/gui_gtk.pro proto/gui_gtk4.pro proto/gui_motif.pro proto/gui_xmdlg.pro proto/gui_gtk_x11.pro proto/gui_x11.pro proto/gui_w32.pro proto/gui_photon.pro

# }}}
@@ -3416,6 +3418,9 @@ objects/gui_gtk4_cb.o: gui_gtk4_cb.c
objects/gui_gtk4_da.o: gui_gtk4_da.c
$(CCC) -o $@ gui_gtk4_da.c

+objects/gui_gtk4_tb.o: gui_gtk4_tb.c
+ $(CCC) -o $@ gui_gtk4_tb.c
+

objects/gui_haiku.o: gui_haiku.cc
$(CCC) -o $@ gui_haiku.cc
@@ -4513,7 +4518,7 @@ objects/gui_gtk4.o: auto/osdef.h gui_gtk4.c vim.h protodef.h auto/config.h featu
structs.h regexp.h gui.h libvterm/include/vterm.h \
libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
globals.h errors.h gui_gtk4_f.h auto/gui_gtk_gresources.h \
- gui_gtk4_da.h
+ gui_gtk4_cb.h gui_gtk4_da.h gui_gtk4_tb.h
objects/gui_gtk4_f.o: auto/osdef.h gui_gtk4_f.c vim.h protodef.h auto/config.h feature.h \
os_unix.h ascii.h keymap.h termdefs.h macros.h option.h \
beval.h structs.h regexp.h gui.h \
@@ -4529,6 +4534,11 @@ objects/gui_gtk4_da.o: auto/osdef.h gui_gtk4_da.c vim.h protodef.h auto/config.h
beval.h structs.h regexp.h gui.h \
libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \
ex_cmds.h spell.h proto.h globals.h errors.h gui_gtk4_da.h
+objects/gui_gtk4_tb.o: auto/osdef.h gui_gtk4_tb.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h ascii.h keymap.h termdefs.h macros.h option.h \
+ beval.h structs.h regexp.h gui.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h errors.h gui_gtk4_tb.h
objects/gui_gtk_f.o: auto/osdef.h gui_gtk_f.c vim.h protodef.h auto/config.h feature.h \
os_unix.h ascii.h keymap.h termdefs.h macros.h option.h \
beval.h structs.h regexp.h gui.h \
diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c
index 8a11027b7..27cf55422 100644
--- a/src/gui_gtk4.c
+++ b/src/gui_gtk4.c
@@ -33,6 +33,9 @@
#ifdef USE_GTK4_SNAPSHOT
# include "gui_gtk4_da.h"
#endif
+#ifdef FEAT_TOOLBAR
+# include "gui_gtk4_tb.h"
+#endif

/*
* Geometry string parser, replacing XParseGeometry to remove X11 dependency.
@@ -508,10 +511,11 @@ gui_mch_init(void)
#endif

#ifdef FEAT_TOOLBAR
- gui.toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gui.toolbar = vim_toolbar_new();
gtk_widget_set_name(gui.toolbar, "vim-toolbar");
gtk_widget_set_visible(gui.toolbar, FALSE);
gtk_box_append(GTK_BOX(vbox), gui.toolbar);
+ vim_toolbar_set_style(VIM_TOOLBAR(gui.toolbar), toolbar_flags, tbis_flags);
#endif

#ifdef FEAT_GUI_TABLINE
@@ -973,7 +977,12 @@ gui_mch_enable_menu(int showit)
gui_mch_show_toolbar(int showit)
{
if (gui.toolbar != NULL)
+ {
gtk_widget_set_visible(gui.toolbar, showit);
+ if (showit)
+ vim_toolbar_set_style(VIM_TOOLBAR(gui.toolbar),
+ toolbar_flags, tbis_flags);
+ }
}
#endif

@@ -4472,7 +4481,7 @@ gui_mch_add_menu(vimmenu_T *menu, int idx UNUSED)
}

void
-gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
+gui_mch_add_menu_item(vimmenu_T *menu, int idx)
{
vimmenu_T *parent = menu->parent;

@@ -4481,32 +4490,32 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
{
if (menu_is_separator(menu->name))
{
- GtkWidget *sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
- gtk_box_append(GTK_BOX(gui.toolbar), sep);
- menu->id = sep;
+ menu->id =
+ vim_toolbar_insert_separator(VIM_TOOLBAR(gui.toolbar), idx);
}
else
{
GtkWidget *btn;
GtkWidget *icon;
+ char_u *text;
char_u *tooltip;

- icon = create_toolbar_icon(menu);
- btn = gtk_button_new();
- gtk_button_set_child(GTK_BUTTON(btn), icon);
- gtk_widget_set_focusable(btn, FALSE);
- gtk_widget_add_css_class(btn, "flat");
-
+ text = CONVERT_TO_UTF8(menu->dname);
tooltip = CONVERT_TO_UTF8(menu->strings[MENU_INDEX_TIP]);
- if (tooltip != NULL && utf_valid_string(tooltip, NULL))
- gtk_widget_set_tooltip_text(btn, (const gchar *)tooltip);
- CONVERT_TO_UTF8_FREE(tooltip);
+ if (tooltip != NULL && !utf_valid_string(tooltip, NULL))
+ CONVERT_TO_UTF8_FREE(tooltip);
+
+ icon = create_toolbar_icon(menu);
+ btn = vim_toolbar_insert_button(VIM_TOOLBAR(gui.toolbar),
+ icon, (const char *)text, idx);
+ gtk_widget_set_tooltip_text(btn, (const gchar *)tooltip);

g_signal_connect(btn, "clicked",
G_CALLBACK(toolbar_button_clicked_cb), menu);

- gtk_box_append(GTK_BOX(gui.toolbar), btn);
menu->id = btn;
+ CONVERT_TO_UTF8_FREE(text);
+ CONVERT_TO_UTF8_FREE(tooltip);
}
return;
}
@@ -4523,7 +4532,8 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
{
// GMenu doesn't have real separators; use a section
GMenu *section = g_menu_new();
- g_menu_append_section(parent_menu, NULL, G_MENU_MODEL(section));
+ g_menu_insert_section(parent_menu, idx, NULL,
+ G_MENU_MODEL(section));
g_object_unref(section);
menu->id = NULL;
}
@@ -4552,7 +4562,7 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)

label = CONVERT_TO_UTF8(menu->dname);
vim_snprintf(detailed, sizeof(detailed), "menu.%s", action_name);
- g_menu_append(parent_menu, (const char *)label, detailed);
+ g_menu_insert(parent_menu, idx, (const char *)label, detailed);
CONVERT_TO_UTF8_FREE(label);

menu->id = (GtkWidget *)1; // non-NULL marker
@@ -4570,8 +4580,17 @@ gui_mch_toggle_tearoffs(int enable UNUSED)
}

void
-gui_mch_menu_set_tip(vimmenu_T *menu UNUSED)
+gui_mch_menu_set_tip(vimmenu_T *menu)
{
+ char_u *tooltip;
+
+ if (menu->id == NULL || menu->parent == NULL || gui.toolbar == NULL)
+ return;
+
+ tooltip = CONVERT_TO_UTF8(menu->strings[MENU_INDEX_TIP]);
+ if (tooltip != NULL && utf_valid_string(tooltip, NULL))
+ gtk_widget_set_tooltip_text(menu->id, (const char *)tooltip);
+ CONVERT_TO_UTF8_FREE(tooltip);
}

/*
diff --git a/src/gui_gtk4_f.c b/src/gui_gtk4_f.c
index cd71122b1..52941874f 100644
--- a/src/gui_gtk4_f.c
+++ b/src/gui_gtk4_f.c
@@ -69,7 +69,7 @@ vim_form_dispose(GObject *obj)
static void
vim_form_class_init(VimFormClass *class)
{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
GObjectClass *obj_class = G_OBJECT_CLASS(class);

widget_class->snapshot = vim_form_snapshot;
diff --git a/src/gui_gtk4_tb.c b/src/gui_gtk4_tb.c
new file mode 100644
index 000000000..e3ed80b47
--- /dev/null
+++ b/src/gui_gtk4_tb.c
@@ -0,0 +1,455 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_TOOLBAR
+
+#include <gtk/gtk.h>
+#include "gui_gtk4_tb.h"
+
+/*
+ * GTK4 removed GtkToolbar, so this is our version of it.
+ */
+struct _VimToolbar
+{
+ GtkWidget parent;
+
+ int style; // TOOLBAR_* flags
+ int iconsize; // TBIS_* values
+
+ GList *items;
+
+ GtkWidget *root;
+ GtkWidget *strip;
+
+ GtkWidget *overflow_btn;
+ GtkWidget *overflow_box;
+};
+
+G_DEFINE_TYPE(VimToolbar, vim_toolbar, GTK_TYPE_WIDGET)
+
+ static void vim_toolbar_size_allocate(GtkWidget *widget, int width, int height, int baseline);
+ static void vim_toolbar_measure(GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline);
+
+ static void
+vim_toolbar_dispose(GObject *object)
+{
+ VimToolbar *self = VIM_TOOLBAR(object);
+
+ g_clear_list(&self->items, g_object_unref);
+ g_clear_pointer(&self->root, gtk_widget_unparent);
+
+ G_OBJECT_CLASS(vim_toolbar_parent_class)->dispose(object);
+}
+
+ static void
+vim_toolbar_class_init(VimToolbarClass *class)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
+ GObjectClass *obj_class = G_OBJECT_CLASS(class);
+
+ widget_class->size_allocate = vim_toolbar_size_allocate;
+ widget_class->measure = vim_toolbar_measure;
+
+ obj_class->dispose = vim_toolbar_dispose;
+
+ gtk_widget_class_set_css_name(widget_class, "toolbar");
+}
+
+ static void
+vim_toolbar_init(VimToolbar *self)
+{
+ GtkWidget *popover;
+
+ self->style = TOOLBAR_ICONS | TOOLBAR_TOOLTIPS;
+ self->iconsize = TBIS_MEDIUM;
+
+ self->root = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
+ gtk_widget_set_parent(self->root, GTK_WIDGET(self));
+
+ self->strip = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_hexpand(self->strip, TRUE);
+ gtk_widget_set_halign(self->strip, GTK_ALIGN_START);
+ gtk_widget_set_overflow(self->strip, GTK_OVERFLOW_HIDDEN);
+ gtk_box_append(GTK_BOX(self->root), self->strip);
+
+ self->overflow_btn = gtk_menu_button_new();
+ gtk_widget_set_hexpand(self->overflow_btn, FALSE);
+ gtk_widget_set_halign(self->overflow_btn, GTK_ALIGN_END);
+ gtk_widget_add_css_class(self->overflow_btn, "flat");
+ gtk_box_append(GTK_BOX(self->root), self->overflow_btn);
+ g_object_set_data(G_OBJECT(self->overflow_btn),
+ "toolbar-width", GINT_TO_POINTER(-1));
+
+ popover = gtk_popover_new();
+ self->overflow_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
+ gtk_popover_set_child(GTK_POPOVER(popover), self->overflow_box);
+ gtk_popover_set_has_arrow(GTK_POPOVER(popover), FALSE);
+
+ gtk_menu_button_set_popover(GTK_MENU_BUTTON(self->overflow_btn), popover);
+}
+
+ GtkWidget *
+vim_toolbar_new(void)
+{
+ return g_object_new(VIM_TYPE_TOOLBAR, NULL);
+}
+
+/*
+ * Inser the widget at the given index, then queue a size allocate to check for
+ * overflowing items.
+ */
+ static void
+vim_toolbar_insert(VimToolbar *self, GtkWidget *widget, int idx)
+{
+ GtkWidget *cur_child = gtk_widget_get_first_child(self->strip);
+ int i = 0;
+
+ while (cur_child != NULL && i != idx - 1)
+ {
+ cur_child = gtk_widget_get_next_sibling(cur_child);
+ i++;
+ }
+
+ gtk_box_insert_child_after(GTK_BOX(self->strip), widget, cur_child);
+ self->items = g_list_insert(self->items, g_object_ref(widget), idx);
+ gtk_widget_queue_allocate(GTK_WIDGET(self));
+}
+
+/*
+ * Update "btn" according to "style" and "iconsize".
+ */
+ static void
+set_button_style(GtkWidget *btn, int style, int iconsize, gboolean invalidate)
+{
+ GtkWidget *box;
+ GtkWidget *icon;
+ GtkWidget *label;
+
+ if (GTK_IS_SEPARATOR(btn))
+ return;
+
+ box = gtk_button_get_child(GTK_BUTTON(btn));
+ if (style & TOOLBAR_HORIZ)
+ {
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(box),
+ GTK_ORIENTATION_HORIZONTAL);
+ gtk_box_set_spacing(GTK_BOX(box), 8);
+ }
+ else
+ {
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(box),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_box_set_spacing(GTK_BOX(box), 4);
+ }
+
+ gtk_widget_set_has_tooltip(btn, style & TOOLBAR_TOOLTIPS);
+
+ icon = g_object_get_data(G_OBJECT(btn), "icon");
+ if (icon != NULL)
+ {
+ if (style & TOOLBAR_ICONS)
+ {
+ GtkIconSize size;
+
+ switch (iconsize)
+ {
+ case TBIS_TINY:
+ case TBIS_SMALL:
+ case TBIS_MEDIUM:
+ size = GTK_ICON_SIZE_NORMAL;
+ break;
+ case TBIS_LARGE:
+ case TBIS_HUGE:
+ case TBIS_GIANT:
+ size = GTK_ICON_SIZE_LARGE;
+ break;
+ default:
+ size = GTK_ICON_SIZE_NORMAL;
+ break;
+ }
+ gtk_image_set_icon_size(GTK_IMAGE(icon), size);
+ gtk_widget_set_visible(icon, TRUE);
+ }
+ else
+ gtk_widget_set_visible(icon, FALSE);
+ }
+
+ label = g_object_get_data(G_OBJECT(btn), "label");
+ if (label != NULL)
+ gtk_widget_set_visible(label, style & TOOLBAR_TEXT);
+
+ // Used to cache width in toolbar ("self->strip"). -1 means not calculated
+ // yet.
+ if (invalidate)
+ g_object_set_data(G_OBJECT(btn), "toolbar-width", GINT_TO_POINTER(-1));
+}
+
+/*
+ * Add a new toolbar button at the given index and return the widget. "icon" and
+ * "text" may be NULL..
+ */
+ GtkWidget *
+vim_toolbar_insert_button(
+ VimToolbar *self,
+ GtkWidget *icon,
+ const char *text,
+ int idx)
+{
+ GtkWidget *btn = gtk_button_new();
+ GtkWidget *box;
+
+ gtk_widget_add_css_class(btn, "flat");
+ box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+
+ gtk_button_set_child(GTK_BUTTON(btn), box);
+
+ if (icon != NULL)
+ {
+ gtk_widget_set_valign (icon, GTK_ALIGN_CENTER);
+ gtk_widget_set_vexpand (icon, TRUE);
+ gtk_box_append(GTK_BOX(box), icon);
+ g_object_set_data(G_OBJECT(btn), "icon", icon);
+ }
+ if (text != NULL)
+ {
+ GtkWidget *label = gtk_label_new(text);
+
+ gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+ gtk_widget_set_vexpand (label, TRUE);
+ gtk_box_append(GTK_BOX(box), label);
+ g_object_set_data(G_OBJECT(btn), "label", label);
+ }
+
+ set_button_style(btn, self->style, self->iconsize, TRUE);
+
+ vim_toolbar_insert(self, btn, idx);
+ return btn;
+}
+
+/*
+ * Insert a toolbar separator at the given index and return the widget.
+ */
+ GtkWidget *
+vim_toolbar_insert_separator(VimToolbar *self, int idx)
+{
+ GtkWidget *sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
+
+ g_object_set_data(G_OBJECT(sep), "toolbar-width", GINT_TO_POINTER(-1));
+ vim_toolbar_insert(self, sep, idx);
+ return sep;
+}
+
+/*
+ * Update the style and iconsize of the toolbar
+ */
+ void
+vim_toolbar_set_style(VimToolbar *self, int style, int iconsize)
+{
+ GtkWidget *cur_child = gtk_widget_get_first_child(self->strip);
+
+ if (style == self->style && self->iconsize == iconsize)
+ return;
+
+ self->style = style;
+ self->iconsize = iconsize;
+
+ while (cur_child != NULL)
+ {
+ if (!GTK_IS_SEPARATOR(cur_child))
+ set_button_style(cur_child, style, iconsize, TRUE);
+ cur_child = gtk_widget_get_next_sibling(cur_child);
+ }
+
+ cur_child = gtk_widget_get_first_child(self->overflow_box);
+ while (cur_child != NULL)
+ {
+ if (!GTK_IS_SEPARATOR(cur_child))
+ set_button_style(cur_child, style, iconsize, TRUE);
+ cur_child = gtk_widget_get_next_sibling(cur_child);
+ }
+ // Sizes may have changed
+ gtk_widget_queue_allocate(GTK_WIDGET(self));
+}
+
+/*
+ * If "overflow" is TRUE, then move "item" from the toolbar to the overflow, and
+ * vice versa.
+ */
+ static void
+vim_toolbar_move_item_to(
+ VimToolbar *self,
+ GtkWidget *item,
+ gboolean overflow)
+{
+ GtkBox *from, *to;
+
+ to = overflow ? GTK_BOX(self->overflow_box) : GTK_BOX(self->strip);
+ if (gtk_widget_get_parent(item) == GTK_WIDGET(to))
+ return;
+
+ from = overflow ? GTK_BOX(self->strip) : GTK_BOX(self->overflow_box);
+
+ gtk_box_remove(from, item);
+ gtk_box_append(to, item);
+
+ if (GTK_IS_SEPARATOR(item))
+ gtk_widget_set_visible(item, !overflow);
+ else
+ {
+ if (overflow)
+ {
+ int style = self->style;
+
+ // Force set these flags for the overflow menu, to mimic what GTK3
+ // GtkToolbar does.
+ style |= TOOLBAR_HORIZ;
+ style |= TOOLBAR_TEXT;
+ style |= TOOLBAR_ICONS;
+ set_button_style(item, style, self->iconsize, FALSE);
+ }
+ else
+ set_button_style(item, self->style, self->iconsize, FALSE);
+ }
+}
+
+ static int
+get_item_width(GtkWidget *item)
+{
+ int toolbar_width = -1;
+
+ // Always use cached width for item, because width in overflow menu is
+ // different (GtkBox is in horizontal layout). Also use it for separators,
+ // since if its not visible, then width is zero.
+ toolbar_width = GPOINTER_TO_INT(
+ g_object_get_data(G_OBJECT(item), "toolbar-width"));
+
+ if (toolbar_width == -1)
+ {
+ GtkRequisition min_req, nat_req;
+ gtk_widget_get_preferred_size(item, &min_req, &nat_req);
+ toolbar_width = MAX(min_req.width, nat_req.width);
+
+ // Save width for later
+ g_object_set_data(G_OBJECT(item),
+ "toolbar-width", GINT_TO_POINTER(toolbar_width));
+ }
+ return toolbar_width;
+}
+
+ static void
+vim_toolbar_size_allocate(
+ GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ VimToolbar *self = VIM_TOOLBAR(widget);
+ GtkAllocation alloc;
+ int used = 0;
+ int avail;
+ GList *overflow_ele = NULL;
+ GtkWidget *child;
+
+ avail = width - get_item_width(self->overflow_btn);
+
+ for (GList *ele = self->items; ele != NULL; ele = ele->next)
+ {
+ GtkWidget *item = ele->data;
+ int toolbar_width = get_item_width(item);
+
+ if (used + toolbar_width > avail)
+ {
+ overflow_ele = ele;
+ break;
+ }
+ else
+ vim_toolbar_move_item_to(self, item, FALSE);
+ used += toolbar_width;
+ }
+
+ if (overflow_ele != NULL)
+ {
+ int remaining = width - used;
+ gboolean need_overflow_btn = FALSE;
+
+ // Move all items in the overflow to the toolbar, so we can add them
+ // in the correct order back again. Also check if the overflow button is
+ // still needed (can fit all toolbar items by disabling it).
+ while ((child = gtk_widget_get_first_child(self->overflow_box))
+ != NULL)
+ vim_toolbar_move_item_to(self, child, FALSE);
+
+ for (GList *ele = overflow_ele; ele != NULL; ele = ele->next)
+ {
+ remaining -= get_item_width(ele->data);
+ if (remaining < 0)
+ {
+ need_overflow_btn = TRUE;
+ break;
+ }
+ }
+
+ if (need_overflow_btn)
+ for (; overflow_ele != NULL; overflow_ele = overflow_ele->next)
+ vim_toolbar_move_item_to(self, overflow_ele->data, TRUE);
+ gtk_widget_set_visible(self->overflow_btn, need_overflow_btn);
+ }
+ else
+ gtk_widget_set_visible(self->overflow_btn, FALSE);
+
+ alloc.x = alloc.y = 0;
+ alloc.width = width;
+ alloc.height = height;
+
+ gtk_widget_size_allocate(self->root, &alloc, baseline);
+}
+
+ static void
+vim_toolbar_measure(
+ GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *min,
+ int *nat,
+ int *min_baseline,
+ int *nat_baseline)
+{
+ VimToolbar *self = VIM_TOOLBAR(widget);
+ int strip_min = 0, strip_nat = 0;
+ int obtn_min = 0, obtn_nat = 0;
+
+ gtk_widget_measure(self->strip, orientation, for_size,
+ &strip_min, &strip_nat, NULL, NULL);
+ gtk_widget_measure(self->overflow_btn, orientation, for_size,
+ &obtn_min, &obtn_nat, NULL, NULL);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (min != NULL)
+ *min = obtn_min;
+ if (nat != NULL)
+ *nat = strip_nat + obtn_nat;
+ }
+ else
+ {
+ if (min != NULL)
+ *min = MAX(strip_min, obtn_min);
+ if (nat != NULL)
+ *nat = MAX(strip_nat, obtn_nat);
+ }
+
+ if (min_baseline != NULL)
+ *min_baseline = -1;
+ if (nat_baseline != NULL)
+ *nat_baseline = -1;
+}
+
+#endif // FEAT_TOOLBAR
diff --git a/src/gui_gtk4_tb.h b/src/gui_gtk4_tb.h
new file mode 100644
index 000000000..d3ff4f782
--- /dev/null
+++ b/src/gui_gtk4_tb.h
@@ -0,0 +1,31 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+#ifndef GUI_GTK4_TB_H
+#define GUI_GTK4_TB_H
+
+#include "vim.h"
+
+#ifdef FEAT_TOOLBAR
+
+# include <gtk/gtk.h>
+
+# define VIM_TYPE_TOOLBAR (vim_toolbar_get_type())
+G_DECLARE_FINAL_TYPE(VimToolbar, vim_toolbar, VIM, TOOLBAR, GtkWidget)
+
+typedef struct _VimToolbarItem VimToolbarItem;
+
+GtkWidget *vim_toolbar_new(void);
+GtkWidget *vim_toolbar_insert_button(VimToolbar *self, GtkWidget *icon, const char *text, int idx);
+GtkWidget *vim_toolbar_insert_separator(VimToolbar *self, int idx);
+void vim_toolbar_set_style(VimToolbar *self, int style, int iconsize);
+
+#endif
+
+#endif
diff --git a/src/version.c b/src/version.c
index c404029ad..e4f09bcab 100644
--- a/src/version.c
+++ b/src/version.c
@@ -759,6 +759,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 669,
/**/
668,
/**/
Reply all
Reply to author
Forward
0 new messages