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.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Foxe Chen
2026-06-02 17:44:42 +00:00
committed by Christian Brabandt
parent 18c6b91ca9
commit 3dc1ece6af
6 changed files with 288 additions and 328 deletions
+5
View File
@@ -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.
+90 -48
View File
@@ -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);
+180 -235
View File
@@ -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
GtkWidget *
gui_gtk_form_new(void)
static void
vim_form_dispose(GObject *obj)
{
return GTK_WIDGET(g_object_new(GTK_TYPE_FORM, NULL));
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);
}
void
gui_gtk_form_put(
GtkForm *form,
GtkWidget *child_widget,
gint x,
gint y)
static void
vim_form_class_init(VimFormClass *class)
{
GtkFormChild *child;
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
GObjectClass *obj_class = G_OBJECT_CLASS(class);
g_return_if_fail(GTK_IS_FORM(form));
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;
child = g_new(GtkFormChild, 1);
if (child == NULL)
return;
obj_class->dispose = vim_form_dispose;
}
child->widget = child_widget;
static void
vim_form_init(VimForm *self)
{
}
GtkWidget *
vim_form_new(void)
{
return g_object_new(VIM_TYPE_FORM, NULL);
}
/*
* Transform the child
*/
static void
vim_form_position_child(VimForm *self, VimFormChild *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);
}
/*
* 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(VimFormChild, 1);
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,80 +174,85 @@ 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)
static void
vim_form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot)
{
g_return_if_fail(GTK_IS_FORM(form));
++form->freeze_count;
}
VimForm *self = VIM_FORM(widget);
void
gui_gtk_form_thaw(GtkForm *form)
{
g_return_if_fail(GTK_IS_FORM(form));
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)
static gboolean
vim_form_resize_idle_cb(VimForm *self)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
int w, h;
gobject_class->dispose = form_dispose;
self->resize_idle_id = 0;
widget_class->measure = form_measure;
widget_class->size_allocate = form_size_allocate;
widget_class->snapshot = form_snapshot;
widget_class->contains = form_contains;
// Use drawarea's actual allocation, not formwin's
if (gui.drawarea == NULL)
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);
exit:
g_object_unref(self);
return G_SOURCE_REMOVE;
}
static void
gui_gtk_form_init(GtkForm *form)
vim_form_size_allocate(
GtkWidget *widget,
int width,
int height,
int baseline)
{
form->children = NULL;
form->freeze_count = 0;
VimForm *self = VIM_FORM(widget);
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 != self->last_width || height != self->last_height)
{
self->last_width = width;
self->last_height = height;
if (self->resize_idle_id == 0)
self->resize_idle_id = g_idle_add(
(GSourceFunc)vim_form_resize_idle_cb, g_object_ref(self));
}
}
static void
form_measure(
vim_form_measure(
GtkWidget *widget UNUSED,
GtkOrientation orientation UNUSED,
int for_size UNUSED,
@@ -200,135 +267,13 @@ form_measure(
*natural_baseline = -1;
}
static guint form_resize_idle_id = 0;
static int form_last_width = 0;
static int form_last_height = 0;
/*
* 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_resize_idle_cb(gpointer data UNUSED)
{
int w, h;
form_resize_idle_id = 0;
// Use drawarea's actual allocation, not formwin's
if (gui.drawarea == NULL)
return FALSE;
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;
}
static void
form_size_allocate(GtkWidget *widget, int width, int height,
int baseline UNUSED)
{
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)
form_position_child(form, tmp_list->data, TRUE);
// Notify Vim about size change via idle callback
if (width != form_last_width || height != form_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);
}
}
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);
}
}
// 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)
vim_form_contains(GtkWidget *widget UNUSED, double x UNUSED, double y UNUSED)
{
return FALSE;
}
static void
form_dispose(GObject *object)
{
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);
}
// Child positioning using GskTransform
static void
form_position_child(
GtkForm *form UNUSED,
GtkFormChild *child,
gboolean force_allocate)
{
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);
}
}
+10 -45
View File
@@ -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" {
#define VIM_TYPE_FORM (vim_form_get_type())
G_DECLARE_FINAL_TYPE(VimForm, vim_form, VIM, FORM, GtkWidget)
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);
#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);
void gui_gtk_form_freeze(GtkForm *form);
void gui_gtk_form_thaw(GtkForm *form);
#ifdef __cplusplus
}
#endif
#endif // GUI_GTK4_FORM_H
+1
View File
@@ -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);
+2
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
587,
/**/
586,
/**/