mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
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:
committed by
Christian Brabandt
parent
18c6b91ca9
commit
3dc1ece6af
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
587,
|
||||
/**/
|
||||
586,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user