patch 9.2.0587: GTK4: left scrollbar overlaps drawarea
Commit:
https://github.com/vim/vim/commit/3dc1ece6afe4a8d04c9a5e660e16ba3d229029a9
Author: Foxe Chen <
chen...@gmail.com>
Date: Tue Jun 2 17:44:42 2026 +0000
patch 9.2.0587: GTK4: left scrollbar overlaps drawarea
Problem: GTK4: the drawarea is wrapped in a GtkOverlay with the
scrollbar form layered on top, so the left scrollbar
appears over the drawarea instead of beside it.
Solution: Place the drawarea and the scrollbars as siblings inside
the form widget, removing the GtkOverlay. Add
gui_mch_update_scrollbar_size() to query the actual
scrollbar dimensions and call it from gui_set_shellsize(),
rename GtkForm to VimForm so the GTK namespace is not used
(Foxe Chen).
closes: #20375
Signed-off-by: Foxe Chen <
chen...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/gui.c b/src/gui.c
index b0235eec2..2b5c0f24a 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -1703,6 +1703,11 @@ gui_set_shellsize(
if (!gui.shell_created)
return;
+#if defined(FEAT_GUI_GTK) && defined(USE_GTK4)
+ // Get the scrollbar width + height if possible
+ gui_mch_update_scrollbar_size();
+#endif
+
#if defined(MSWIN) || defined(FEAT_GUI_GTK)
// If not setting to a user specified size and maximized, calculate the
// number of characters that fit in the maximized window.
diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c
index d6d32b7cc..20390879a 100644
--- a/src/gui_gtk4.c
+++ b/src/gui_gtk4.c
@@ -499,30 +499,21 @@ gui_mch_init(void)
G_CALLBACK(on_tab_reordered), NULL);
#endif
- // The form widget manages absolute positioning of scrollbars.
- gui.formwin = gui_gtk_form_new();
+ // The form widget manages absolute positioning of scrollbars and the draw
+ // area.
+ gui.formwin = vim_form_new();
gtk_widget_set_name(gui.formwin, "vim-gtk-form");
- // formwin is overlaid on top of drawarea for scrollbar positioning.
- // GtkForm's contains() returns FALSE so empty-area clicks fall through
- // to the drawarea, while the scrollbar children still receive events.
+ gtk_widget_set_vexpand(gui.formwin, TRUE);
+ gtk_widget_set_hexpand(gui.formwin, TRUE);
+ gtk_box_append(GTK_BOX(vbox), gui.formwin);
// The drawing area for the editor content.
- // Placed in an overlay so it fills the formwin, with scrollbars on top.
gui.drawarea = gtk_drawing_area_new();
gui.surface = NULL;
gtk_widget_set_focusable(gui.drawarea, TRUE);
gtk_widget_set_vexpand(gui.drawarea, TRUE);
gtk_widget_set_hexpand(gui.drawarea, TRUE);
-
- {
- // Use GtkOverlay: drawarea as the main child, formwin as overlay
- GtkWidget *overlay = gtk_overlay_new();
- gtk_overlay_set_child(GTK_OVERLAY(overlay), gui.drawarea);
- gtk_overlay_add_overlay(GTK_OVERLAY(overlay), gui.formwin);
- gtk_widget_set_vexpand(overlay, TRUE);
- gtk_widget_set_hexpand(overlay, TRUE);
- gtk_box_append(GTK_BOX(vbox), overlay);
- }
+ vim_form_put(VIM_FORM(gui.formwin), gui.drawarea, 0, 0);
// Set up drawing.
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(gui.drawarea),
@@ -3007,8 +2998,8 @@ gui_gtk_draw_string_ext(
column_offset = len;
}
else
-not_ascii:
{
+not_ascii:;
PangoAttrList *attr_list;
GList *item_list;
int cluster_width;
@@ -4269,10 +4260,7 @@ gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max)
gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h)
{
if (sb->id != NULL)
- {
- gtk_widget_set_size_request(sb->id, w, h);
- gui_gtk_form_move(GTK_FORM(gui.formwin), sb->id, x, y);
- }
+ vim_form_move_resize(VIM_FORM(gui.formwin), sb->id, x, y, w, h);
}
int
@@ -4317,24 +4305,21 @@ adjustment_value_changed(GtkAdjustment *adj, gpointer data UNUSED)
void
gui_mch_create_scrollbar(scrollbar_T *sb, int orient)
{
+ GtkAdjustment *adj;
if (orient == SBAR_HORIZ)
sb->id = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
else
sb->id = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
- if (sb->id != NULL && GTK_IS_SCROLLBAR(sb->id))
- {
- GtkAdjustment *adj = gtk_scrollbar_get_adjustment(GTK_SCROLLBAR(sb->id));
+ gtk_widget_add_css_class(sb->id, "vim-scrollbar");
+ adj = gtk_scrollbar_get_adjustment(GTK_SCROLLBAR(sb->id));
- gtk_widget_set_visible(sb->id, FALSE);
- gui_gtk_form_put(GTK_FORM(gui.formwin), sb->id, 0, 0);
- if (adj != NULL && G_IS_OBJECT(adj))
- {
- g_object_set_data(G_OBJECT(adj), "vim-sb", (gpointer)sb);
- g_signal_connect(G_OBJECT(adj), "value-changed",
- G_CALLBACK(adjustment_value_changed), NULL);
- }
- }
+ gtk_widget_set_visible(sb->id, FALSE);
+ vim_form_put(VIM_FORM(gui.formwin), sb->id, 0, 0);
+
+ g_object_set_data(G_OBJECT(adj), "vim-sb", (gpointer)sb);
+ g_signal_connect(G_OBJECT(adj), "value-changed",
+ G_CALLBACK(adjustment_value_changed), NULL);
}
void
@@ -4342,11 +4327,68 @@ gui_mch_destroy_scrollbar(scrollbar_T *sb)
{
if (sb->id != NULL)
{
- gui_gtk_form_remove(GTK_FORM(gui.formwin), sb->id);
+ vim_form_remove(VIM_FORM(gui.formwin), sb->id);
sb->id = NULL;
}
}
+/*
+ * Try getting the actual size of the scrollbar, and update gui.scrollbar_width
+ * and gui.scrollbar_height.
+ */
+ void
+gui_mch_update_scrollbar_size(void)
+{
+ win_T *wp;
+ int w = -1, h = -1;
+ GtkWidget *sbar;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ sbar = wp->w_scrollbars[SBAR_LEFT].id;
+
+ if (sbar == NULL || !gtk_widget_get_visible(sbar)
+ || (!gui.which_scrollbars[SBAR_LEFT]
+ && wp->w_scrollbars[SBAR_RIGHT].id != NULL))
+ sbar = wp->w_scrollbars[SBAR_RIGHT].id;
+
+ if (sbar != NULL && gtk_widget_get_visible(sbar))
+ {
+ GtkRequisition min, nat;
+ int sw;
+
+ // Use preferred size, since widget may not have its size allocated
+ // yet.
+ gtk_widget_get_preferred_size(sbar, &min, &nat);
+ sw = MAX(min.width, nat.width);
+ if (sw > 0)
+ {
+ w = sw;
+ break;
+ }
+ }
+
+ }
+
+ sbar =
gui.bottom_sbar.id;
+ if (sbar != NULL && gtk_widget_get_visible(sbar))
+ {
+ GtkRequisition min, nat;
+ int sh;
+
+ gtk_widget_get_preferred_size(sbar, &min, &nat);
+ sh = MAX(min.height, nat.height);
+
+ if (sh > 0)
+ h = sh;
+ }
+
+ if (w != -1)
+ gui.scrollbar_width = w;
+ if (h != -1)
+ gui.scrollbar_height = h;
+}
+
/*
* ============================================================
* Text area position
@@ -4358,11 +4400,11 @@ gui_mch_set_text_area_pos(int x, int y, int w, int h)
{
last_text_area_w = w;
last_text_area_h = h;
- // Don't use gui_gtk_form_move_resize for drawarea because its
+ // Don't use vim_form_move_resize for drawarea because its
// set_size_request would prevent the window from shrinking.
// Just update position; the actual allocation is handled by
- // form_size_allocate which gives drawarea the formwin's full size.
- gui_gtk_form_move(GTK_FORM(gui.formwin), gui.drawarea, x, y);
+ // vim_form_size_allocate which gives drawarea the formwin's full size.
+ vim_form_move(VIM_FORM(gui.formwin), gui.drawarea, x, y);
// Surface sizing is owned by drawarea_resize_cb; don't recreate it
// here. Recreating on every text-area change wiped any preserved
@@ -4704,7 +4746,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
char_u *entry_text;
int wword = FALSE;
int mcase = !p_ic;
- GtkWidget *vbox, *grid, *hbox, *tmp, *btn;
+ GtkWidget *vertbox, *grid, *hbox, *tmp, *btn;
gboolean sensitive;
frdp = do_replace ? &repl_widgets : &find_widgets;
@@ -4748,18 +4790,18 @@ find_replace_dialog_create(char_u *arg, int do_replace)
g_signal_connect(frdp->dialog, "destroy",
G_CALLBACK(dialog_destroyed_cb), &frdp->dialog);
- vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
- gtk_widget_set_margin_start(vbox, 12);
- gtk_widget_set_margin_end(vbox, 12);
- gtk_widget_set_margin_top(vbox, 12);
- gtk_widget_set_margin_bottom(vbox, 12);
- gtk_window_set_child(GTK_WINDOW(frdp->dialog), vbox);
+ vertbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
+ gtk_widget_set_margin_start(vertbox, 12);
+ gtk_widget_set_margin_end(vertbox, 12);
+ gtk_widget_set_margin_top(vertbox, 12);
+ gtk_widget_set_margin_bottom(vertbox, 12);
+ gtk_window_set_child(GTK_WINDOW(frdp->dialog), vertbox);
// Grid for labels + entries
grid = gtk_grid_new();
gtk_grid_set_row_spacing(GTK_GRID(grid), 6);
gtk_grid_set_column_spacing(GTK_GRID(grid), 6);
- gtk_box_append(GTK_BOX(vbox), grid);
+ gtk_box_append(GTK_BOX(vertbox), grid);
// "Find what:" label + entry
tmp = gtk_label_new(_("Find what:"));
@@ -4787,7 +4829,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
// Checkboxes
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_box_append(GTK_BOX(vbox), hbox);
+ gtk_box_append(GTK_BOX(vertbox), hbox);
frdp->wword = gtk_check_button_new_with_label(_("Match whole word only"));
gtk_check_button_set_active(GTK_CHECK_BUTTON(frdp->wword),
@@ -4801,7 +4843,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
// Direction radio buttons
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_box_append(GTK_BOX(vbox), hbox);
+ gtk_box_append(GTK_BOX(vertbox), hbox);
tmp = gtk_label_new(_("Direction:"));
gtk_box_append(GTK_BOX(hbox), tmp);
@@ -4818,7 +4860,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
// Action buttons
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign(hbox, GTK_ALIGN_END);
- gtk_box_append(GTK_BOX(vbox), hbox);
+ gtk_box_append(GTK_BOX(vertbox), hbox);
btn = gtk_button_new_with_label(_("Find Next"));
gtk_widget_set_sensitive(btn, sensitive);
diff --git a/src/gui_gtk4_f.c b/src/gui_gtk4_f.c
index 80aa7a48d..14ff85f62 100644
--- a/src/gui_gtk4_f.c
+++ b/src/gui_gtk4_f.c
@@ -5,106 +5,168 @@
* 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.
- *
- * GTK4 GtkForm widget - a simple container for absolute child positioning.
- * This is a clean rewrite of gui_gtk_f.c for GTK4.
- *
- * In GTK4, widgets no longer have their own GdkWindows (now GdkSurface),
- * GtkContainer is removed, and child positioning uses GskTransform via
- * gtk_widget_allocate(). This makes the form widget much simpler.
*/
#include "vim.h"
#include <gtk/gtk.h>
#include "gui_gtk4_f.h"
-typedef struct _GtkFormChild GtkFormChild;
-
-struct _GtkFormChild
+/*
+ * Child widget at position (x, y).
+ */
+typedef struct
{
- GtkWidget *widget;
- gint x;
- gint y;
+ GtkWidget *widget;
+ int x;
+ int y;
+} VimFormChild;
+
+/*
+ * Similar to the GtkFixed widget, allows absolute position and sizing of child
+ * widgets within. Vim already has logic for positioning and sizing UI elements,
+ * so this is needed to take advantage of that. We don't use GtkFixed directly
+ * since we need to override some vfuncs.
+ */
+struct _VimForm
+{
+ GtkWidget parent;
+
+ GList *children;
+
+ // See vim_form_size_allocate()
+ guint resize_idle_id;
+ int last_width;
+ int last_height;
};
-// Forward declarations
-static void gui_gtk_form_class_init(GtkFormClass *klass);
-static void gui_gtk_form_init(GtkForm *form);
-static void form_measure(GtkWidget *widget, GtkOrientation orientation,
- int for_size, int *minimum, int *natural,
- int *minimum_baseline, int *natural_baseline);
-static void form_size_allocate(GtkWidget *widget, int width, int height,
- int baseline);
-static void form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot);
-static gboolean form_contains(GtkWidget *widget, double x, double y);
-static void form_dispose(GObject *object);
-static void form_position_child(GtkForm *form, GtkFormChild *child,
- gboolean force_allocate);
+G_DEFINE_TYPE(VimForm, vim_form, GTK_TYPE_WIDGET)
-G_DEFINE_TYPE(GtkForm, gui_gtk_form, GTK_TYPE_WIDGET)
+static void vim_form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot);
+static void vim_form_size_allocate(GtkWidget *widget, int width, int height, int baseline);
+static void vim_form_measure(GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline);
+static gboolean vim_form_contains(GtkWidget *widget, double x, double y);
-// Public interface
+ static void
+vim_form_dispose(GObject *obj)
+{
+ VimForm *self = VIM_FORM(obj);
+ GList *ele = self->children;
+
+ while (ele != NULL)
+ {
+ VimFormChild *child = ele->data;
+
+ ele = ele->next;
+ gtk_widget_unparent(child->widget);
+ g_free(child);
+ }
+ g_list_free(self->children);
+ self->children = NULL;
+
+ G_OBJECT_CLASS(vim_form_parent_class)->dispose(obj);
+}
+
+ static void
+vim_form_class_init(VimFormClass *class)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
+ GObjectClass *obj_class = G_OBJECT_CLASS(class);
+
+ widget_class->snapshot = vim_form_snapshot;
+ widget_class->size_allocate = vim_form_size_allocate;
+ widget_class->measure = vim_form_measure;
+ widget_class->contains = vim_form_contains;
+
+ obj_class->dispose = vim_form_dispose;
+}
+
+ static void
+vim_form_init(VimForm *self)
+{
+
+}
GtkWidget *
-gui_gtk_form_new(void)
+vim_form_new(void)
{
- return GTK_WIDGET(g_object_new(GTK_TYPE_FORM, NULL));
+ return g_object_new(VIM_TYPE_FORM, NULL);
}
- void
-gui_gtk_form_put(
- GtkForm *form,
- GtkWidget *child_widget,
- gint x,
- gint y)
+/*
+ * Transform the child
+ */
+ static void
+vim_form_position_child(VimForm *self, VimFormChild *child)
{
- GtkFormChild *child;
+ GtkRequisition requisition;
+ GskTransform *transform;
+ int w, h;
+
+ gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
+ w = requisition.width;
+ h = requisition.height;
+
+ // If widget has no size request, use parent size
+ if (w <= 0)
+ w = gtk_widget_get_width(GTK_WIDGET(self));
+ if (h <= 0)
+ h = gtk_widget_get_height(GTK_WIDGET(self));
+ if (w <= 0) w = 1;
+ if (h <= 0) h = 1;
+
+ transform = gsk_transform_translate(NULL,
+ &GRAPHENE_POINT_INIT((float)child->x, (float)child->y));
+ gtk_widget_allocate(child->widget, w, h, -1, transform);
+}
- g_return_if_fail(GTK_IS_FORM(form));
+/*
+ * Place the given widget at the point (x, y).
+ */
+ void
+vim_form_put(VimForm *self, GtkWidget *widget, int x, int y)
+{
+ VimFormChild *child;
- child = g_new(GtkFormChild, 1);
- if (child == NULL)
- return;
+ child = g_new(VimFormChild, 1);
- child->widget = child_widget;
+ child->widget = widget;
child->x = x;
child->y = y;
gtk_widget_set_size_request(child->widget, -1, -1);
- form->children = g_list_append(form->children, child);
+ self->children = g_list_append(self->children, child);
- gtk_widget_set_parent(child_widget, GTK_WIDGET(form));
- form_position_child(form, child, TRUE);
+ gtk_widget_set_parent(widget, GTK_WIDGET(self));
+ vim_form_position_child(self, child);
}
+/*
+ * Move the widget (which should have already been added using vim_form_put())
+ * to the given point (x, y).
+ */
void
-gui_gtk_form_move(
- GtkForm *form,
- GtkWidget *child_widget,
- gint x,
- gint y)
+vim_form_move(VimForm *self, GtkWidget *widget, int x, int y)
{
- GList *tmp_list;
-
- g_return_if_fail(GTK_IS_FORM(form));
-
- for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ for (GList *ele = self->children; ele != NULL; ele = ele->next)
{
- GtkFormChild *child = tmp_list->data;
- if (child->widget == child_widget)
+ VimFormChild *child = ele->data;
+ if (child->widget == widget)
{
child->x = x;
child->y = y;
- form_position_child(form, child, TRUE);
+ vim_form_position_child(self, child);
return;
}
}
}
+/*
+ * Move and resize the child.
+ */
void
-gui_gtk_form_move_resize(
- GtkForm *form,
+vim_form_move_resize(
+ VimForm *self,
GtkWidget *widget,
gint x,
gint y,
@@ -112,223 +174,106 @@ gui_gtk_form_move_resize(
gint h)
{
gtk_widget_set_size_request(widget, w, h);
- gui_gtk_form_move(form, widget, x, y);
+ vim_form_move(self, widget, x, y);
}
void
-gui_gtk_form_remove(GtkForm *form, GtkWidget *child_widget)
+vim_form_remove(VimForm *self, GtkWidget *widget)
{
- GList *tmp_list;
-
- g_return_if_fail(GTK_IS_FORM(form));
-
- for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ for (GList *ele = self->children; ele != NULL; ele = ele->next)
{
- GtkFormChild *child = tmp_list->data;
- if (child->widget == child_widget)
+ VimFormChild *child = ele->data;
+ if (child->widget == widget)
{
- form->children = g_list_remove_link(form->children, tmp_list);
- g_list_free_1(tmp_list);
- gtk_widget_unparent(child_widget);
+ self->children = g_list_remove_link(self->children, ele);
+ g_list_free_1(ele);
+ gtk_widget_unparent(widget);
g_free(child);
return;
}
}
}
- void
-gui_gtk_form_freeze(GtkForm *form)
-{
- g_return_if_fail(GTK_IS_FORM(form));
- ++form->freeze_count;
-}
-
- void
-gui_gtk_form_thaw(GtkForm *form)
+ static void
+vim_form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot)
{
- g_return_if_fail(GTK_IS_FORM(form));
+ VimForm *self = VIM_FORM(widget);
- if (!form->freeze_count)
- return;
-
- if (!(--form->freeze_count))
+ for (GList *ele = self->children; ele != NULL; ele = ele->next)
{
- GList *tmp_list;
-
- for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
- form_position_child(form, tmp_list->data, FALSE);
- gtk_widget_queue_draw(GTK_WIDGET(form));
+ VimFormChild *child = ele->data;
+ gtk_widget_snapshot_child(widget, child->widget, snapshot);
}
}
-// GObject/GtkWidget class implementation
-
- static void
-gui_gtk_form_class_init(GtkFormClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
-
- gobject_class->dispose = form_dispose;
-
- widget_class->measure = form_measure;
- widget_class->size_allocate = form_size_allocate;
- widget_class->snapshot = form_snapshot;
- widget_class->contains = form_contains;
-}
-
- static void
-gui_gtk_form_init(GtkForm *form)
-{
- form->children = NULL;
- form->freeze_count = 0;
-}
-
- static void
-form_measure(
- GtkWidget *widget UNUSED,
- GtkOrientation orientation UNUSED,
- int for_size UNUSED,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
-{
- *minimum = 1;
- *natural = 1;
- *minimum_baseline = -1;
- *natural_baseline = -1;
-}
-
-static guint form_resize_idle_id = 0;
-static int form_last_width = 0;
-static int form_last_height = 0;
-
static gboolean
-form_resize_idle_cb(gpointer data UNUSED)
+vim_form_resize_idle_cb(VimForm *self)
{
int w, h;
- form_resize_idle_id = 0;
+ self->resize_idle_id = 0;
// Use drawarea's actual allocation, not formwin's
if (gui.drawarea == NULL)
- return FALSE;
+ goto exit;
w = gtk_widget_get_width(gui.drawarea);
h = gtk_widget_get_height(gui.drawarea);
if (w > 1 && h > 1)
gui_resize_shell(w, h);
- return FALSE;
+exit:
+ g_object_unref(self);
+ return G_SOURCE_REMOVE;
}
static void
-form_size_allocate(GtkWidget *widget, int width, int height,
- int baseline UNUSED)
+vim_form_size_allocate(
+ GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
{
- GtkForm *form;
- GList *tmp_list;
+ VimForm *self = VIM_FORM(widget);
- g_return_if_fail(GTK_IS_FORM(widget));
-
- form = GTK_FORM(widget);
-
- for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
- form_position_child(form, tmp_list->data, TRUE);
+ for (GList *ele = self->children; ele != NULL; ele = ele->next)
+ vim_form_position_child(self, ele->data);
// Notify Vim about size change via idle callback
- if (width != form_last_width || height != form_last_height)
+ if (width != self->last_width || height != self->last_height)
{
- form_last_width = width;
- form_last_height = height;
- if (form_resize_idle_id == 0)
- form_resize_idle_id = g_idle_add(form_resize_idle_cb, NULL);
- }
-}
+ self->last_width = width;
+ self->last_height = height;
- static void
-form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot)
-{
- GtkForm *form;
- GList *tmp_list;
-
- g_return_if_fail(GTK_IS_FORM(widget));
-
- form = GTK_FORM(widget);
-
- for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
- {
- GtkFormChild *child = tmp_list->data;
- if (child->widget != NULL
- && GTK_IS_WIDGET(child->widget)
- && gtk_widget_get_parent(child->widget) == widget)
- gtk_widget_snapshot_child(widget, child->widget, snapshot);
+ if (self->resize_idle_id == 0)
+ self->resize_idle_id = g_idle_add(
+ (GSourceFunc)vim_form_resize_idle_cb, g_object_ref(self));
}
}
-// Make the form itself input-transparent so clicks on its empty area fall
-// through to the drawarea below, while the scrollbar children stay pickable.
- static gboolean
-form_contains(GtkWidget *widget UNUSED, double x UNUSED, double y UNUSED)
-{
- return FALSE;
-}
-
static void
-form_dispose(GObject *object)
+vim_form_measure(
+ GtkWidget *widget UNUSED,
+ GtkOrientation orientation UNUSED,
+ int for_size UNUSED,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
{
- GtkForm *form = GTK_FORM(object);
- GList *tmp_list;
-
- tmp_list = form->children;
- while (tmp_list)
- {
- GtkFormChild *child = tmp_list->data;
- tmp_list = tmp_list->next;
-
- gtk_widget_unparent(child->widget);
- g_free(child);
- }
- g_list_free(form->children);
- form->children = NULL;
-
- G_OBJECT_CLASS(gui_gtk_form_parent_class)->dispose(object);
+ *minimum = 1;
+ *natural = 1;
+ *minimum_baseline = -1;
+ *natural_baseline = -1;
}
-// Child positioning using GskTransform
- static void
-form_position_child(
- GtkForm *form UNUSED,
- GtkFormChild *child,
- gboolean force_allocate)
+/*
+ * Make the form itself input-transparent so clicks on its empty area fall
+ * through to the drawarea below, while the scrollbar children stay pickable.
+ */
+ static gboolean
+vim_form_contains(GtkWidget *widget UNUSED, double x UNUSED, double y UNUSED)
{
- if (!force_allocate)
- return;
-
- if (child->widget == NULL || !GTK_IS_WIDGET(child->widget))
- return;
-
- {
- GtkRequisition requisition;
- GskTransform *transform;
- int w, h;
-
- gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
- w = requisition.width;
- h = requisition.height;
-
- // If widget has no size request (e.g. drawarea), use parent size
- if (w <= 0)
- w = gtk_widget_get_width(GTK_WIDGET(form));
- if (h <= 0)
- h = gtk_widget_get_height(GTK_WIDGET(form));
- if (w <= 0) w = 1;
- if (h <= 0) h = 1;
-
- transform = gsk_transform_translate(NULL,
- &GRAPHENE_POINT_INIT((float)child->x, (float)child->y));
- gtk_widget_allocate(child->widget, w, h, -1, transform);
- }
+ return FALSE;
}
diff --git a/src/gui_gtk4_f.h b/src/gui_gtk4_f.h
index a92706160..d795b86c2 100644
--- a/src/gui_gtk4_f.h
+++ b/src/gui_gtk4_f.h
@@ -4,8 +4,7 @@
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
- *
- * GTK4 GtkForm widget - a simple container for absolute positioning.
+ * See README.txt for an overview of the Vim source code.
*/
#ifndef GUI_GTK4_FORM_H
@@ -13,47 +12,13 @@
#include <gtk/gtk.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GTK_TYPE_FORM (gui_gtk_form_get_type())
-#define GTK_FORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_FORM, GtkForm))
-#define GTK_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_FORM, GtkFormClass))
-#define GTK_IS_FORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_FORM))
-
-typedef struct _GtkForm GtkForm;
-typedef struct _GtkFormClass GtkFormClass;
-
-struct _GtkForm
-{
- GtkWidget widget;
- GList *children;
- gint freeze_count;
-};
-
-struct _GtkFormClass
-{
- GtkWidgetClass parent_class;
-};
-
-GType gui_gtk_form_get_type(void);
-
-GtkWidget *gui_gtk_form_new(void);
-
-void gui_gtk_form_put(GtkForm *form, GtkWidget *widget, gint x, gint y);
-
-void gui_gtk_form_move(GtkForm *form, GtkWidget *widget, gint x, gint y);
-
-void gui_gtk_form_move_resize(GtkForm *form, GtkWidget *widget,
- gint x, gint y, gint w, gint h);
-
-void gui_gtk_form_remove(GtkForm *form, GtkWidget *widget);
+#define VIM_TYPE_FORM (vim_form_get_type())
+G_DECLARE_FINAL_TYPE(VimForm, vim_form, VIM, FORM, GtkWidget)
-void gui_gtk_form_freeze(GtkForm *form);
-void gui_gtk_form_thaw(GtkForm *form);
+GtkWidget *vim_form_new(void);
+void vim_form_put(VimForm *self, GtkWidget *widget, int x, int y);
+void vim_form_move(VimForm *self, GtkWidget *widget, int x, int y);
+void vim_form_move_resize(VimForm *self, GtkWidget *widget, gint x, gint y, gint w, gint h);
+void vim_form_remove(VimForm *self, GtkWidget *widget);
-#ifdef __cplusplus
-}
#endif
-#endif // GUI_GTK4_FORM_H
diff --git a/src/proto/
gui_gtk4.pro b/src/proto/
gui_gtk4.pro
index 4d21e6a70..0a1ba1296 100644
--- a/src/proto/
gui_gtk4.pro
+++ b/src/proto/
gui_gtk4.pro
@@ -99,6 +99,7 @@ int gui_mch_get_scrollbar_xpadding(void);
int gui_mch_get_scrollbar_ypadding(void);
void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+void gui_mch_update_scrollbar_size(void);
void gui_mch_set_text_area_pos(int x, int y, int w, int h);
char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
char_u *gui_mch_browsedir(char_u *title, char_u *initdir);
diff --git a/src/version.c b/src/version.c
index e020aedc5..676c515f9 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 587,
/**/
586,
/**/