Commit: patch 9.2.0865: GTK4: non-hardware accelerated UI is too slow

3 views
Skip to first unread message

Christian Brabandt

unread,
5:00 PM (5 hours ago) 5:00 PM
to vim...@googlegroups.com
patch 9.2.0865: GTK4: non-hardware accelerated UI is too slow

Commit: https://github.com/vim/vim/commit/b56b4a3a6691a610f53f6d7a1ba721af3ad46b35
Author: Foxe Chen <chen...@gmail.com>
Date: Mon Jul 27 20:43:18 2026 +0000

patch 9.2.0865: GTK4: non-hardware accelerated UI is too slow

Problem: GTK4: non-hardware accelerated UI is too slow
Solution: Remove the sofware rendering (cairo) backend, make the GTK4
hardware accelerated rendering the default (Foxe Chen).

closes: #20844

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

diff --git a/runtime/doc/gui_x11.txt b/runtime/doc/gui_x11.txt
index 58467023a..8f37a154c 100644
--- a/runtime/doc/gui_x11.txt
+++ b/runtime/doc/gui_x11.txt
@@ -1,4 +1,4 @@
-*gui_x11.txt* For Vim version 9.2. Last change: 2026 Jun 29
+*gui_x11.txt* For Vim version 9.2. Last change: 2026 Jul 27


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -371,14 +371,6 @@ to use software rendering: >
$ GSK_RENDERER=cairo gvim
$ LIBGL_ALWAYS_SOFTWARE=true gvim
<
- *gtk4-hwaccel*
-If Vim is compiled with the configure option "--enable-gtk4-hwaccel" set, then
-the GTK4 GUI will use GtkSnapshot instead of Cairo, allowing for hardware
-accelerated rendering, which is much faster. Enabling this configure option
-also makes the GTK4 GUI use |+image_gdk| instead of |+image_cairo| for
-rendering popup window images. Note that this feature is currently
-experimental.
-
Tooltip Colors ~
*gtk-tooltip-colors*
Example, which sets the tooltip colors to black on light-yellow: >
diff --git a/runtime/doc/tags b/runtime/doc/tags
index b01ae4204..28c30f03c 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -8260,7 +8260,6 @@ gt tabpage.txt /*gt*
gtk-css gui_x11.txt /*gtk-css*
gtk-tooltip-colors gui_x11.txt /*gtk-tooltip-colors*
gtk3-slow gui_x11.txt /*gtk3-slow*
-gtk4-hwaccel gui_x11.txt /*gtk4-hwaccel*
gtk4-menu-navigation gui_x11.txt /*gtk4-menu-navigation*
gtk4-slow gui_x11.txt /*gtk4-slow*
gu change.txt /*gu*
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index efe88e949..738e95bdb 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.2. Last change: 2026 Jul 22
+*version9.txt* For Vim version 9.2. Last change: 2026 Jul 27


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52663,7 +52663,6 @@ Platform specific ~
-----------------
- support OpenType font features in 'guifont' for DirectWrite (Win32)
- Include strptime() fallback for MS-Windows
-- Hardware-accelerated rendering for the GTK4 GUI via |gtk4-hwaccel|.
- The NSIS installer has been reworked (Win32):
- Support per-user and per-machine install.
- Change the install directory structure.
diff --git a/src/auto/configure b/src/auto/configure
index ffdff9662..8fd4ba3b7 100755
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -862,7 +862,6 @@ enable_gui
enable_gtk2_check
enable_gnome_check
enable_gtk4_check
-enable_gtk4_hwaccel
enable_gtk3_check
enable_motif_check
enable_gtktest
@@ -1542,7 +1541,6 @@ Optional Features:
--enable-gtk2-check If auto-select GUI, check for GTK+ 2 default=yes
--enable-gnome-check If GTK GUI, check for GNOME default=no
--enable-gtk4-check If auto-select GUI, check for GTK 4 default=yes
- --enable-gtk4-hwaccel Use hardware accelerated rendering backend for GTK4 default=no
--enable-gtk3-check If auto-select GUI, check for GTK+ 3 default=yes
--enable-motif-check If auto-select GUI, check for Motif default=yes
--disable-gtktest Do not try to compile and run a test GTK program
@@ -10583,28 +10581,6 @@ printf "%s
" "$enable_gtk4_check" >&6; }
fi
fi

-if test "x$SKIP_GTK4" != "xYES" -a "$enable_gui_canon" = "gtk4"; then
- { printf "%s
" "$as_me:${as_lineno-$LINENO}: checking --enable-gtk4-hwaccel argument" >&5
-printf %s "checking --enable-gtk4-hwaccel argument... " >&6; }
- # Check whether --enable-gtk4-hwaccel was given.
-if test ${enable_gtk4_hwaccel+y}
-then :
- enableval=$enable_gtk4_hwaccel;
-else case e in #(
- e) enable_gtk4_hwaccel="no" ;;
-esac
-fi
-
- { printf "%s
" "$as_me:${as_lineno-$LINENO}: result: $enable_gtk4_hwaccel" >&5
-printf "%s
" "$enable_gtk4_hwaccel" >&6; }
-
- if test "x$enable_gtk4_hwaccel" = "xyes"; then
- printf "%s
" "#define USE_GTK4_SNAPSHOT 1" >>confdefs.h
-
- fi
-fi
-
-
if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then
{ printf "%s
" "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 3" >&5
printf %s "checking whether or not to look for GTK+ 3... " >&6; }
diff --git a/src/config.h.in b/src/config.h.in
index bb16501ea..d26bd2078 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -499,9 +499,6 @@
/* Define if GTK GUI is to be linked against GTK 4 */
#undef USE_GTK4

-/* Define if GTK4 GUI should use hardware accelerated backend */
-#undef USE_GTK4_SNAPSHOT
-
/* Define if we have isinf() */
#undef HAVE_ISINF

diff --git a/src/configure.ac b/src/configure.ac
index 0cf75308b..654959874 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -2715,19 +2715,6 @@ if test "x$SKIP_GTK4" != "xYES" -a "$enable_gui_canon" != "gtk4"; then
fi
fi

-if test "x$SKIP_GTK4" != "xYES" -a "$enable_gui_canon" = "gtk4"; then
- AC_MSG_CHECKING(--enable-gtk4-hwaccel argument)
- AC_ARG_ENABLE(gtk4-hwaccel,
- [ --enable-gtk4-hwaccel Use hardware accelerated rendering backend for GTK4 [default=no]],
- , enable_gtk4_hwaccel="no")
- AC_MSG_RESULT($enable_gtk4_hwaccel)
-
- if test "x$enable_gtk4_hwaccel" = "xyes"; then
- AC_DEFINE(USE_GTK4_SNAPSHOT)
- fi
-fi
-
-
if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then
AC_MSG_CHECKING(whether or not to look for GTK+ 3)
AC_ARG_ENABLE(gtk3-check,
diff --git a/src/feature.h b/src/feature.h
index 3a0b6931c..5d5512615 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -1132,7 +1132,7 @@
#endif

#if defined(FEAT_IMAGE) && defined(FEAT_GUI_GTK)
-# ifdef USE_GTK4_SNAPSHOT
+# ifdef USE_GTK4
# define FEAT_IMAGE_GDK
# else
# define FEAT_IMAGE_CAIRO
diff --git a/src/gui.c b/src/gui.c
index d58f9f2cc..5d6eae105 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -24,7 +24,7 @@ static void set_guifontwide(char_u *font_name);
static void gui_check_pos(void);
static void gui_reset_scroll_region(void);
static void gui_outstr(char_u *, int);
-#ifndef USE_GTK4_SNAPSHOT
+#ifndef USE_GTK4
static int gui_screenchar(int off, int flags, guicolor_T fg, guicolor_T bg, int back);
#endif
static int gui_outstr_nowrap(char_u *s, int len, int flags, guicolor_T fg, guicolor_T bg, int back);
@@ -1199,7 +1199,7 @@ gui_update_cursor(
int cattr; // cursor attributes
int attr;
attrentry_T *aep = NULL;
-#if (defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN)) && !defined(USE_GTK4_SNAPSHOT)
+#if (defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN)) && !defined(USE_GTK4)
bool lig_left = false, lig_right = false;
#endif

@@ -1367,7 +1367,7 @@ gui_update_cursor(
*/
if (!gui.in_focus)
{
-#ifdef USE_GTK4_SNAPSHOT
+#ifdef USE_GTK4
gui_gtk4_draw_cursor(cbg, cfg, -1, -1);
#else
gui_mch_draw_hollow_cursor(cbg);
@@ -1375,7 +1375,7 @@ gui_update_cursor(
return;
}

-#ifdef USE_GTK4_SNAPSHOT
+#ifdef USE_GTK4
// Make sure that character underneath is drawn again in case it is part of
// a ligature.
gui_redraw_block(gui.row, gui.col, gui.row, gui.col, GUI_MON_NOCLEAR);
@@ -1392,7 +1392,7 @@ gui_update_cursor(
{
gui_redraw_block(gui.row, c + 1, gui.row, gui.col - 1,
GUI_MON_NOCLEAR);
-# ifndef USE_GTK4_SNAPSHOT
+# ifndef USE_GTK4
lig_left = true;
# endif
}
@@ -1406,7 +1406,7 @@ gui_update_cursor(
{
gui_redraw_block(gui.row, gui.col + 1, gui.row, c - 1,
GUI_MON_NOCLEAR);
-# ifndef USE_GTK4_SNAPSHOT
+# ifndef USE_GTK4
lig_right = true;
# endif
}
@@ -1416,7 +1416,7 @@ gui_update_cursor(
// it again.
gui.cursor_is_valid = true;

-# ifndef USE_GTK4_SNAPSHOT
+# ifndef USE_GTK4
if ((lig_left || lig_right) && shape->shape != SHAPE_BLOCK)
{
// Because the cursor is not drawn with gui_screenchar(), must blit the
@@ -1435,7 +1435,7 @@ gui_update_cursor(
old_hl_mask = gui.highlight_mask;
if (shape->shape == SHAPE_BLOCK)
{
-#ifdef USE_GTK4_SNAPSHOT
+#ifdef USE_GTK4
gui_gtk4_draw_cursor(cbg, cfg, 0, 0);
#else
/*
@@ -1484,7 +1484,7 @@ gui_update_cursor(
}
#endif
}
-#ifdef USE_GTK4_SNAPSHOT
+#ifdef USE_GTK4
gui_gtk4_draw_cursor(cbg, cfg, cur_width, cur_height);
#else
gui_mch_draw_part_cursor(cur_width, cur_height, cbg);
@@ -1496,7 +1496,7 @@ gui_update_cursor(

// Doesn't seem to work for MSWindows. We call gui_redraw_block() above
// for GtkSnapshot.
-#if !defined(FEAT_GUI_MSWIN) && !defined(USE_GTK4_SNAPSHOT)
+#if !defined(FEAT_GUI_MSWIN) && !defined(USE_GTK4)
gui.highlight_mask = ScreenAttrs[LineOffset[gui.row] + gui.col];
(void)gui_screenchar(LineOffset[gui.row] + gui.col,
GUI_MON_TRS_CURSOR | GUI_MON_NOCLEAR,
@@ -1689,14 +1689,14 @@ again:
gui.num_cols = (pixel_width - gui_get_base_width()) / gui.char_width;
gui.num_rows = (pixel_height - gui_get_base_height()) / gui.char_height;

-#ifdef USE_GTK4_SNAPSHOT
+#ifdef USE_GTK4
gui_gtk4_update_size();
#endif

gui_position_components(pixel_width);
gui_reset_scroll_region();

-#if defined(FEAT_GUI_GTK) && defined(USE_GTK4) && !defined(USE_GTK4_SNAPSHOT)
+#if defined(FEAT_GUI_GTK) && defined(USE_GTK4) && !defined(USE_GTK4)
// We do not resize the draw area via the "resize" signal. This is because
// when the window is resized, the form widget is the one that is resized,
// so let that call gui_resize_shell() which will allocate the surface and
@@ -1726,7 +1726,7 @@ again:

gui_update_scrollbars(TRUE);
gui_update_cursor(FALSE, TRUE);
-#if defined(FEAT_GUI_GTK) && defined(USE_GTK4_SNAPSHOT)
+#if defined(FEAT_GUI_GTK) && defined(USE_GTK4)
gui_gtk4_calculate_bleed(pixel_width, pixel_height);
#endif
#if defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)
@@ -1899,7 +1899,7 @@ gui_set_shellsize(
gui_update_scrollbars(TRUE);
gui_reset_scroll_region();

-#if defined(FEAT_GUI_GTK) && defined(USE_GTK4_SNAPSHOT)
+#if defined(FEAT_GUI_GTK) && defined(USE_GTK4)
gui_gtk4_calculate_bleed(width, height);
#endif
}
@@ -2293,7 +2293,7 @@ gui_outstr(char_u *s, int len)
}
}

-#ifndef USE_GTK4_SNAPSHOT
+#ifndef USE_GTK4
/*
* Output one character (may be one or two display cells).
* Caller must check for valid "off".
diff --git a/src/gui.h b/src/gui.h
index 16f13e477..e2232982e 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -285,7 +285,7 @@ typedef struct Gui
#ifdef FEAT_DIRECTX
bool directx_enabled; // DirectX (DirectWrite) rendering active
#endif
-#if defined(FEAT_GUI_GTK) && defined(USE_GTK4_SNAPSHOT)
+#if defined(FEAT_GUI_GTK) && defined(USE_GTK4)
int bleed_right; // Number of pixels to bleed bg color right
int bleed_bot; // Number of pixels to bleed bg color down
#endif
@@ -400,11 +400,9 @@ typedef struct Gui
GdkColor *bgcolor; // GDK-styled background color
GdkColor *spcolor; // GDK-styled special color
# endif
-# if defined(USE_GTK3) || defined(USE_GTK4)
-# ifndef USE_GTK4_SNAPSHOT
+# if defined(USE_GTK3) && !defined(USE_GTK4)
cairo_surface_t *surface; // drawarea surface
-# endif
-# else
+# elif !defined(USE_GTK4)
GdkGC *text_gc; // cached GC for normal text
# endif
PangoContext *text_context; // the context used for all text
diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c
index 6e5dbfda1..93851af7c 100644
--- a/src/gui_gtk4.c
+++ b/src/gui_gtk4.c
@@ -30,9 +30,7 @@
#include <gtk/gtk.h>
#include "gui_gtk4_f.h"
#include "gui_gtk4_cb.h"
-#ifdef USE_GTK4_SNAPSHOT
-# include "gui_gtk4_da.h"
-#endif
+#include "gui_gtk4_da.h"
#ifdef FEAT_TOOLBAR
# include "gui_gtk4_tb.h"
#endif
@@ -271,9 +269,6 @@ modifiers_gdk2vim(guint state)
static GtkWidget *vbox; // the main vertical box

// Forward declarations for event callbacks
-#ifndef USE_GTK4_SNAPSHOT
-static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data);
-#endif
static gboolean key_press_event(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer data);
static void key_release_event(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer data);
static void button_press_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data);
@@ -299,9 +294,6 @@ static int query_pointer_pos(int *x, int *y, GdkModifierType *state);
static void mainwin_fullscreened_cb(GObject *obj, GParamSpec *pspec, gpointer user_data);
static void drawarea_realize_cb(GtkWidget *widget, gpointer data);
static void drawarea_unrealize_cb(GtkWidget *widget, gpointer data);
-#ifndef USE_GTK4_SNAPSHOT
-static cairo_surface_t *create_backing_surface(int width, int height);
-#endif
static void scale_factor_cb(GdkSurface *surface, GParamSpec *pspec, void *udata);
static void clipboard_changed_cb(GdkClipboard *clipboard, gpointer user_data);
#ifdef FEAT_MENU
@@ -554,22 +546,12 @@ gui_mch_init(void)
gtk_box_append(GTK_BOX(vbox), gui.formwin);

// The drawing area for the editor content.
-#ifdef USE_GTK4_SNAPSHOT
gui.drawarea = vim_draw_area_new();
-#else
- gui.drawarea = gtk_drawing_area_new();
- gui.surface = NULL;
-#endif
gtk_widget_set_focusable(gui.drawarea, TRUE);
gtk_widget_set_vexpand(gui.drawarea, TRUE);
gtk_widget_set_hexpand(gui.drawarea, TRUE);
vim_form_put(VIM_FORM(gui.formwin), gui.drawarea, 0, 0);

-#ifndef USE_GTK4_SNAPSHOT
- // Set up drawing.
- gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(gui.drawarea),
- (GtkDrawingAreaDrawFunc)draw_event, NULL, NULL);
-#endif
g_signal_connect(G_OBJECT(gui.drawarea), "realize",
G_CALLBACK(drawarea_realize_cb), NULL);
g_signal_connect(G_OBJECT(gui.drawarea), "unrealize",
@@ -664,31 +646,9 @@ gui_mch_init(void)
return OK;
}

-#ifndef USE_GTK4_SNAPSHOT
-/*
- * Called when the foreground or background color has been changed.
- */
- static void
-surface_fill_bg(void)
-{
- if (gui.surface != NULL)
- {
- cairo_t *cr = cairo_create(gui.surface);
- cairo_set_source_rgba(cr,
- gui.bgcolor->red, gui.bgcolor->green,
- gui.bgcolor->blue, gui.bgcolor->alpha);
- cairo_paint(cr);
- cairo_destroy(cr);
- }
-}
-#endif
-
void
gui_mch_new_colors(void)
{
-#ifndef USE_GTK4_SNAPSHOT
- surface_fill_bg();
-#endif
if (gui.drawarea != NULL && gtk_widget_get_realized(gui.drawarea))
gtk_widget_queue_draw(gui.drawarea);
}
@@ -1427,7 +1387,6 @@ gui_mch_get_rgb(guicolor_T pixel)
* ============================================================
*/

-#ifdef USE_GTK4_SNAPSHOT
void
gui_gtk4_update_size(void)
{
@@ -1435,7 +1394,7 @@ gui_gtk4_update_size(void)
gui.num_rows, gui.num_cols);
}

-# ifdef FEAT_NETBEANS_INTG
+#ifdef FEAT_NETBEANS_INTG
void
gui_gtk4_add_multisign(
cairo_surface_t *surf,
@@ -1447,90 +1406,13 @@ gui_gtk4_add_multisign(
vim_draw_area_add_multisign(VIM_DRAW_AREA(gui.drawarea), surf, row, col,
width, height);
}
-# endif
-#else // USE_GTK4_SNAPSHOT
-static void set_cairo_source_from_pixel(cairo_t *cr, guicolor_T pixel);
-
- static void
-draw_event(GtkDrawingArea *area UNUSED, cairo_t *cr,
- int width, int height, gpointer data UNUSED)
-{
- // Surface creation/resizing is handled by drawarea_resize_cb.
- // Here we only paint the surface to the widget.
-
- // Fill background with Vim's background color
- set_cairo_source_from_pixel(cr, gui.back_pixel);
- cairo_rectangle(cr, 0, 0, width, height);
- cairo_fill(cr);
-
- // Paint the Vim surface on top
- if (gui.surface != NULL)
- {
- cairo_set_source_surface(cr, gui.surface, 0, 0);
- cairo_paint(cr);
- }
-}
-
- static void
-set_cairo_source_from_pixel(cairo_t *cr, guicolor_T pixel)
-{
- cairo_set_source_rgb(cr,
- ((pixel & 0xff0000) >> 16) / 255.0,
- ((pixel & 0xff00) >> 8) / 255.0,
- (pixel & 0xff) / 255.0);
-}
-
- static int
-get_drawarea_scale(void)
-{
- int scale = 1;
-
- if (gui.drawarea != NULL)
- scale = gtk_widget_get_scale_factor(gui.drawarea);
- if (scale < 1)
- scale = 1;
- return scale;
-}
-
- static cairo_surface_t *
-create_backing_surface(int width, int height)
-{
- cairo_surface_t *surf;
- int scale;
-
- if (width <= 0 || height <= 0)
- return NULL;
-
- scale = get_drawarea_scale();
- surf = cairo_image_surface_create(
- CAIRO_FORMAT_ARGB32, width * scale, height * scale);
- cairo_surface_set_device_scale(surf, (double)scale, (double)scale);
- return surf;
-}
-#endif // !USE_GTK4_SNAPSHOT
+#endif

void
gui_mch_clear_block(int row1, int col1, int row2, int col2)
{
-#ifdef USE_GTK4_SNAPSHOT
vim_draw_area_clear_block(VIM_DRAW_AREA(gui.drawarea), row1,
col1, row2, col2);
-#else
- cairo_t *cr;
-
- if (gui.surface == NULL)
- return;
-
- cr = cairo_create(gui.surface);
- set_cairo_source_from_pixel(cr, gui.back_pixel);
- cairo_rectangle(cr,
- FILL_X(col1), FILL_Y(row1),
- (col2 - col1 + 1) * gui.char_width,
- (row2 - row1 + 1) * gui.char_height);
- cairo_fill(cr);
- cairo_destroy(cr);
-#endif
-
if (gui.drawarea != NULL)
gtk_widget_queue_draw(gui.drawarea);
}
@@ -1538,20 +1420,7 @@ gui_mch_clear_block(int row1, int col1, int row2, int col2)
void
gui_mch_clear_all(void)
{
-#ifdef USE_GTK4_SNAPSHOT
vim_draw_area_clear(VIM_DRAW_AREA(gui.drawarea));
-#else
- cairo_t *cr;
-
- if (gui.surface == NULL)
- return;
-
- cr = cairo_create(gui.surface);
- set_cairo_source_from_pixel(cr, gui.back_pixel);
- cairo_paint(cr);
- cairo_destroy(cr);
-#endif
-
if (gui.drawarea != NULL)
gtk_widget_queue_draw(gui.drawarea);
}
@@ -1687,52 +1556,12 @@ gui_mch_draw_popup_image(
}
#endif // FEAT_IMAGE_CAIRO

-#ifndef USE_GTK4_SNAPSHOT
- static void
-surface_copy_rect(int dest_x, int dest_y,
- int src_x, int src_y,
- int width, int height)
-{
- cairo_t *cr;
- cairo_surface_t *tmp;
-
- if (gui.surface == NULL || width <= 0 || height <= 0)
- return;
-
- // Use a temporary surface to avoid overlap issues
- tmp = create_backing_surface(width, height);
- if (tmp == NULL)
- return;
- cr = cairo_create(tmp);
- cairo_set_source_surface(cr, gui.surface, -src_x, -src_y);
- cairo_paint(cr);
- cairo_destroy(cr);
-
- cr = cairo_create(gui.surface);
- cairo_set_source_surface(cr, tmp, dest_x, dest_y);
- cairo_paint(cr);
- cairo_destroy(cr);
- cairo_surface_destroy(tmp);
-}
-#endif
-
void
gui_mch_delete_lines(int row, int num_lines)
{
-#ifdef USE_GTK4_SNAPSHOT
vim_draw_area_move_block(VIM_DRAW_AREA(gui.drawarea),
row, row + num_lines, gui.scroll_region_bot,
gui.scroll_region_left, gui.scroll_region_right);
-#else
- int ncols = gui.scroll_region_right - gui.scroll_region_left + 1;
- int nrows = gui.scroll_region_bot - row + 1;
- int src_nrows = nrows - num_lines;
-
- surface_copy_rect(
- FILL_X(gui.scroll_region_left), FILL_Y(row),
- FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
- gui.char_width * ncols + 1, gui.char_height * src_nrows);
-#endif
gui_clear_block(
gui.scroll_region_bot - num_lines + 1, gui.scroll_region_left,
gui.scroll_region_bot, gui.scroll_region_right);
@@ -1743,20 +1572,9 @@ gui_mch_delete_lines(int row, int num_lines)
void
gui_mch_insert_lines(int row, int num_lines)
{
-#ifdef USE_GTK4_SNAPSHOT
vim_draw_area_move_block(VIM_DRAW_AREA(gui.drawarea),
row + num_lines, row, gui.scroll_region_bot - num_lines,
gui.scroll_region_left, gui.scroll_region_right);
-#else
- int ncols = gui.scroll_region_right - gui.scroll_region_left + 1;
- int nrows = gui.scroll_region_bot - row + 1;
- int src_nrows = nrows - num_lines;
-
- surface_copy_rect(
- FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
- FILL_X(gui.scroll_region_left), FILL_Y(row),
- gui.char_width * ncols + 1, gui.char_height * src_nrows);
-#endif
gui_clear_block(
row, gui.scroll_region_left,
row + num_lines - 1, gui.scroll_region_right);
@@ -1764,7 +1582,6 @@ gui_mch_insert_lines(int row, int num_lines)
gtk_widget_queue_draw(gui.drawarea);
}

-#if defined(USE_GTK4_SNAPSHOT) || defined(PROTO)
/*
* See vim_draw_area_set_cursor() for more information
*/
@@ -1776,70 +1593,11 @@ gui_gtk4_draw_cursor(guicolor_T bg, guicolor_T fg, int w, int h)
vim_draw_area_set_cursor(VIM_DRAW_AREA(gui.drawarea), w, h);
gtk_widget_queue_draw(gui.drawarea);
}
-#endif
-
-#if !defined(USE_GTK4_SNAPSHOT) || defined(PROTO)
- void
-gui_mch_draw_hollow_cursor(guicolor_T color)
-{
- cairo_t *cr;
- int i = 1;
-
- if (gui.surface == NULL)
- return;
-
- cr = cairo_create(gui.surface);
- gui_mch_set_fg_color(color);
- cairo_set_source_rgba(cr,
- gui.fgcolor->red, gui.fgcolor->green,
- gui.fgcolor->blue, gui.fgcolor->alpha);
- if (mb_lefthalve(gui.row, gui.col))
- i = 2;
- cairo_set_line_width(cr, 1.0);
- cairo_rectangle(cr,
- FILL_X(gui.col) + 0.5, FILL_Y(gui.row) + 0.5,
- i * gui.char_width - 1, gui.char_height - 1);
- cairo_stroke(cr);
- cairo_destroy(cr);
-
- gtk_widget_queue_draw(gui.drawarea);
-}
-
- void
-gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
-{
- cairo_t *cr;
-
- if (gui.surface == NULL)
- return;
-
- gui_mch_set_fg_color(color);
- cr = cairo_create(gui.surface);
- cairo_set_source_rgba(cr,
- gui.fgcolor->red, gui.fgcolor->green,
- gui.fgcolor->blue, gui.fgcolor->alpha);
- cairo_rectangle(cr,
-# ifdef FEAT_RIGHTLEFT
- CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
-# endif
- FILL_X(gui.col), FILL_Y(gui.row) + gui.char_height - h,
- w, h);
- cairo_fill(cr);
- cairo_destroy(cr);
-
- gtk_widget_queue_draw(gui.drawarea);
-}
-#endif

void
gui_mch_flash(int msec)
{
// Invert the screen, wait, then invert back
-#ifndef USE_GTK4_SNAPSHOT
- if (gui.surface == NULL)
- return;
-#endif
-
gui_mch_invert_rectangle(0, 0, (int)Rows - 1, (int)Columns - 1);
gui_mch_flush();
ui_delay((long)msec, TRUE);
@@ -1849,24 +1607,7 @@ gui_mch_flash(int msec)
void
gui_mch_invert_rectangle(int r, int c, int nr, int nc)
{
-#ifdef USE_GTK4_SNAPSHOT
vim_draw_area_invert_block(VIM_DRAW_AREA(gui.drawarea), r, c, nr, nc);
-#else
- cairo_t *cr;
-
- if (gui.surface == NULL)
- return;
-
- cr = cairo_create(gui.surface);
- cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE);
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_rectangle(cr,
- FILL_X(c), FILL_Y(r),
- (nc + 1) * gui.char_width, (nr + 1) * gui.char_height);
- cairo_fill(cr);
- cairo_destroy(cr);
-#endif
-
gtk_widget_queue_draw(gui.drawarea);
}

@@ -2318,39 +2059,15 @@ focus_out_event(GtkEventControllerFocus *controller UNUSED,
static void
drawarea_realize_cb(GtkWidget *widget UNUSED, gpointer data UNUSED)
{
-#ifndef USE_GTK4_SNAPSHOT
- int w, h;
-
- // Use formwin size since drawarea may not have its final size yet
- if (gui.formwin != NULL)
- {
- w = gtk_widget_get_width(gui.formwin);
- h = gtk_widget_get_height(gui.formwin);
- }
- else
- {
- w = gtk_widget_get_width(widget);
- h = gtk_widget_get_height(widget);
- }
-
- if (w <= 0) w = 800;
- if (h <= 0) h = 600;
+ // Use GdkSurface, as that handles fractional scale values.
+ GdkSurface *surface = gtk_native_get_surface(
+ gtk_widget_get_native(gui.drawarea));
+ double old = gui.scale;

- if (gui.surface != NULL)
- cairo_surface_destroy(gui.surface);
- gui.surface = create_backing_surface(w, h);
-#endif
- {
- // Use GdkSurface, as that handles fractional scale values.
- GdkSurface *surface = gtk_native_get_surface(
- gtk_widget_get_native(gui.drawarea));
- double old = gui.scale;
-
- gui.scale = gdk_surface_get_scale(surface);
- popup_update_scale(old);
- g_signal_connect(G_OBJECT(surface), "notify::scale",
- G_CALLBACK(scale_factor_cb), NULL);
- }
+ gui.scale = gdk_surface_get_scale(surface);
+ popup_update_scale(old);
+ g_signal_connect(G_OBJECT(surface), "notify::scale",
+ G_CALLBACK(scale_factor_cb), NULL);

gui_mch_new_colors();
}
@@ -2361,98 +2078,18 @@ drawarea_unrealize_cb(GtkWidget *widget UNUSED, gpointer data UNUSED)
#ifdef FEAT_XIM
im_shutdown();
#endif
-#ifndef USE_GTK4_SNAPSHOT
- if (gui.surface != NULL)
- {
- cairo_surface_destroy(gui.surface);
- gui.surface = NULL;
- }
-#endif
-}
-
-#ifndef USE_GTK4_SNAPSHOT
- void
-gui_gtk4_resize(int width, int height)
-{
- cairo_t *cr;
- cairo_surface_t *old_surface;
- int scale = get_drawarea_scale();
-
- if (width <= 0 || height <= 0)
- return;
-
- // Keep the backing surface in sync with the drawing area so GTK keeps
- // showing the previous frame. Re-creating it preserves the old
- // contents.
- if (gui.surface != NULL)
- {
- int sw = cairo_image_surface_get_width(gui.surface) / scale;
- int sh = cairo_image_surface_get_height(gui.surface) / scale;
- if (sw != width || sh != height)
- {
- old_surface = gui.surface;
- gui.surface = create_backing_surface(width, height);
- if (gui.surface != NULL)
- {
- cr = cairo_create(gui.surface);
- set_cairo_source_from_pixel(cr, gui.back_pixel);
- cairo_paint(cr);
- cairo_set_source_surface(cr, old_surface, 0, 0);
- cairo_paint(cr);
- cairo_destroy(cr);
- }
- cairo_surface_destroy(old_surface);
- }
- }
- else
- {
- gui.surface = create_backing_surface(width, height);
- if (gui.surface != NULL)
- {
- cr = cairo_create(gui.surface);
- set_cairo_source_from_pixel(cr, gui.back_pixel);
- cairo_paint(cr);
- cairo_destroy(cr);
- }
- }
}
-#endif

static void
scale_factor_cb(GdkSurface *surface,
GParamSpec *pspec UNUSED,
void *udata UNUSED)
{
-#ifndef USE_GTK4_SNAPSHOT
- int w, h;
-
- w = gtk_widget_get_width(gui.drawarea);
- h = gtk_widget_get_height(gui.drawarea);
- if (w <= 0 || h <= 0)
- return;
-
- if (gui.surface != NULL)
- cairo_surface_destroy(gui.surface);
- gui.surface = create_backing_surface(w, h);
-
- if (gui.surface != NULL)
- {
- cairo_t *cr = cairo_create(gui.surface);
- set_cairo_source_from_pixel(cr, gui.back_pixel);
- cairo_paint(cr);
- cairo_destroy(cr);
- }
- gtk_widget_queue_draw(gui.drawarea);
- if (gui.in_use)
- redraw_all_later(UPD_CLEAR);
-#endif
#if defined(FEAT_IMAGE)
- {
- double old = gui.scale;
+ double old = gui.scale;

- gui.scale = gdk_surface_get_scale(surface);
- popup_update_scale(old);
- }
+ gui.scale = gdk_surface_get_scale(surface);
+ popup_update_scale(old);
#endif
}

@@ -3454,7 +3091,6 @@ tabline_menu_press_event(
void
gui_mch_drawsign(int row, int col, int typenr)
{
-# ifdef USE_GTK4_SNAPSHOT
GdkTexture *sign;

sign = (GdkTexture *)sign_get_image(typenr);
@@ -3463,42 +3099,6 @@ gui_mch_drawsign(int row, int col, int typenr)

vim_draw_area_add_sign(VIM_DRAW_AREA(gui.drawarea), sign,
row, col, SIGN_WIDTH, SIGN_HEIGHT);
-# else
- GdkPixbuf *sign;
- cairo_t *cr;
- int width, height;
-
- sign = (GdkPixbuf *)sign_get_image(typenr);
- if (sign == NULL || gui.surface == NULL)
- return;
-
- cr = cairo_create(gui.surface);
-
- width = gdk_pixbuf_get_width(sign);
- height = gdk_pixbuf_get_height(sign);
-
- // Scale to fit the sign area if needed
- if (width != SIGN_WIDTH || height != SIGN_HEIGHT)
- {
- GdkPixbuf *scaled = gdk_pixbuf_scale_simple(sign,
- SIGN_WIDTH, SIGN_HEIGHT, GDK_INTERP_BILINEAR);
- if (scaled != NULL)
- {
- gdk_cairo_set_source_pixbuf(cr, scaled,
- FILL_X(col), FILL_Y(row));
- g_object_unref(scaled);
- }
- else
- gdk_cairo_set_source_pixbuf(cr, sign,
- FILL_X(col), FILL_Y(row));
- }
- else
- gdk_cairo_set_source_pixbuf(cr, sign,
- FILL_X(col), FILL_Y(row));
-
- cairo_paint(cr);
- cairo_destroy(cr);
-# endif

gtk_widget_queue_draw(gui.drawarea);
}
@@ -3508,21 +3108,13 @@ gui_mch_register_sign(char_u *signfile)
{
if (signfile[0] != NUL && signfile[0] != '-' && gui.in_use)
{
- GError *error = NULL;
-# ifdef USE_GTK4_SNAPSHOT
+ GError *error = NULL;
GdkTexture *sign;

sign = gdk_texture_new_from_filename((const char *)signfile,
&error);
if (sign != NULL)
return sign;
-# else
- GdkPixbuf *sign;
-
- sign = gdk_pixbuf_new_from_file((const char *)signfile, &error);
- if (error == NULL)
- return sign;
-# endif

semsg("E255: %s", error->message);
g_error_free(error);
@@ -3544,417 +3136,6 @@ gui_mch_destroy_sign(void *sign)
* ============================================================
*/

-#ifndef USE_GTK4_SNAPSHOT
-/*
- * Ligature and text drawing support.
- * Ported from gui_gtk_x11.c (GTK3) to support 'guiligatures' in GTK4.
- */
-
-# define INSERT_PANGO_ATTR(Attribute, AttrList, Start, End) \
- G_STMT_START{ \
- PangoAttribute *tmp_attr_; \
- tmp_attr_ = (Attribute); \
- tmp_attr_->start_index = (Start); \
- tmp_attr_->end_index = (End); \
- pango_attr_list_insert((AttrList), tmp_attr_); \
- }G_STMT_END
-
-/*
- * Apply the 'guifontwide' font to double-width characters in the string.
- */
- static void
-apply_wide_font_attr(char_u *s, int len, PangoAttrList *attr_list)
-{
- char_u *start = NULL;
- char_u *p;
- int uc;
-
- for (p = s; p < s + len; p += utf_byte2len(*p))
- {
- uc = utf_ptr2char(p);
-
- if (start == NULL)
- {
- if (uc >= 0x80 && utf_char2cells(uc) == 2)
- start = p;
- }
- else if (uc < 0x80
- || (utf_char2cells(uc) != 2 && !utf_iscomposing(uc)))
- {
- INSERT_PANGO_ATTR(pango_attr_font_desc_new(gui.wide_font),
- attr_list, start - s, p - s);
- start = NULL;
- }
- }
-
- if (start != NULL)
- INSERT_PANGO_ATTR(pango_attr_font_desc_new(gui.wide_font),
- attr_list, start - s, len);
-}
-
-/*
- * Count the number of display cells occupied by a glyph cluster.
- */
- static int
-count_cluster_cells(char_u *s, PangoItem *item,
- PangoGlyphString *glyphs, int i,
- int *cluster_width,
- int *last_glyph_rbearing)
-{
- char_u *p;
- int next;
- int start, end;
- int width;
- int uc;
- int cellcount = 0;
-
- width = glyphs->glyphs[i].geometry.width;
-
- for (next = i + 1; next < glyphs->num_glyphs; ++next)
- {
- if (glyphs->glyphs[next].attr.is_cluster_start)
- break;
- else if (glyphs->glyphs[next].geometry.width > width)
- width = glyphs->glyphs[next].geometry.width;
- }
-
- start = item->offset + glyphs->log_clusters[i];
- end = item->offset + ((next < glyphs->num_glyphs) ?
- glyphs->log_clusters[next] : item->length);
-
- for (p = s + start; p < s + end; p += utf_byte2len(*p))
- {
- uc = utf_ptr2char(p);
- if (uc < 0x80)
- ++cellcount;
- else if (!utf_iscomposing(uc))
- cellcount += utf_char2cells(uc);
- }
-
- if (last_glyph_rbearing != NULL
- && cellcount > 0 && next == glyphs->num_glyphs)
- {
- PangoRectangle ink_rect;
-
- pango_font_get_glyph_extents(item->analysis.font,
- glyphs->glyphs[i].glyph,
- &ink_rect, NULL);
-
- if (PANGO_RBEARING(ink_rect) > 0)
- *last_glyph_rbearing = PANGO_RBEARING(ink_rect);
- }
-
- if (cellcount > 0)
- *cluster_width = width;
-
- return cellcount;
-}
-
-/*
- * Handle combining characters that form a zero-width cluster.
- */
- static void
-setup_zero_width_cluster(PangoItem *item, PangoGlyphInfo *glyph,
- int last_cellcount, int last_cluster_width,
- int last_glyph_rbearing)
-{
- PangoRectangle ink_rect;
- PangoRectangle logical_rect;
- int width;
-
- width = last_cellcount * gui.char_width * PANGO_SCALE;
- glyph->geometry.x_offset = -width + MAX(0, width - last_cluster_width) / 2;
- glyph->geometry.width = 0;
-
- pango_font_get_glyph_extents(item->analysis.font,
- glyph->glyph,
- &ink_rect, &logical_rect);
- if (ink_rect.x < 0)
- {
- glyph->geometry.x_offset += last_glyph_rbearing;
- glyph->geometry.y_offset = logical_rect.height
- - (gui.char_height - p_linespace) * PANGO_SCALE;
- }
- else
- glyph->geometry.x_offset = -width + MAX(0, width - ink_rect.width) / 2;
-}
-
-/*
- * Draw a single glyph string segment: background, foreground, and fake bold.
- */
- static void
-draw_glyph_string(int row, int col, int num_cells, int flags,
- PangoFont *font, PangoGlyphString *glyphs,
- cairo_t *cr)
-{
- if (!(flags & DRAW_TRANSP))
- {
- cairo_set_source_rgba(cr,
- gui.bgcolor->red, gui.bgcolor->green, gui.bgcolor->blue,
- gui.bgcolor->alpha);
- cairo_rectangle(cr,
- FILL_X(col), FILL_Y(row),
- num_cells * gui.char_width, gui.char_height);
- cairo_fill(cr);
- }
-
- cairo_set_source_rgba(cr,
- gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
- gui.fgcolor->alpha);
- cairo_move_to(cr, TEXT_X(col), TEXT_Y(row));
- pango_cairo_show_glyph_string(cr, font, glyphs);
-
- // Redraw with offset of 1 to emulate bold
- if ((flags & DRAW_BOLD) && !gui.font_can_bold)
- {
- cairo_move_to(cr, TEXT_X(col) + 1, TEXT_Y(row));
- pango_cairo_show_glyph_string(cr, font, glyphs);
- }
-}
-
-/*
- * Draw underline, undercurl, and strikethrough decorations.
- */
- static void
-draw_under(int flags, int row, int col, int cells, cairo_t *cr)
-{
- // Draw underline
- if (flags & DRAW_UNDERL)
- {
- int y = FILL_Y(row + 1) - 1;
- cairo_set_source_rgba(cr,
- gui.fgcolor->red, gui.fgcolor->green,
- gui.fgcolor->blue, gui.fgcolor->alpha);
- cairo_set_line_width(cr, 1.0);
- cairo_move_to(cr, FILL_X(col), y + 0.5);
- cairo_line_to(cr, FILL_X(col + cells), y + 0.5);
- cairo_stroke(cr);
- }
-
- // Draw undercurl
- if (flags & DRAW_UNDERC)
- {
- static const int val[8] = {1, 0, 0, 0, 1, 2, 2, 2};
- int y = FILL_Y(row + 1) - 1;
- int i, offset;
-
- cairo_set_line_width(cr, 1.0);
- cairo_set_source_rgba(cr,
- gui.spcolor->red, gui.spcolor->green,
- gui.spcolor->blue, gui.spcolor->alpha);
- cairo_move_to(cr, FILL_X(col) + 1, y - 2 + 0.5);
- for (i = FILL_X(col) + 1; i < FILL_X(col + cells); ++i)
- {
- offset = val[i % 8];
- cairo_line_to(cr, i, y - offset + 0.5);
- }
- cairo_stroke(cr);
- }
-
- // Draw strikethrough
- if (flags & DRAW_STRIKE)
- {
- int y = FILL_Y(row) + gui.char_height / 2;
- cairo_set_source_rgba(cr,
- gui.fgcolor->red, gui.fgcolor->green,
- gui.fgcolor->blue, gui.fgcolor->alpha);
- cairo_set_line_width(cr, 1.0);
- cairo_move_to(cr, FILL_X(col), y + 0.5);
- cairo_line_to(cr, FILL_X(col + cells), y + 0.5);
- cairo_stroke(cr);
- }
-}
-
-/*
- * Draw a string of characters on the screen.
- * "force_pango" is set when ligature characters require Pango shaping
- * instead of the fast ASCII glyph cache path.
- * Returns the number of display cells used.
- */
- int
-gui_gtk_draw_string_ext(
- int row,
- int col,
- char_u *s,
- int len,
- int flags,
- int force_pango)
-{
- PangoGlyphString *glyphs;
- int column_offset = 0;
- int i;
- GdkRectangle area;
- cairo_t *cr;
-
- if (gui.text_context == NULL || gui.surface == NULL)
- return len;
-
- // Restrict all drawing to the current screen line.
- area.x = gui.border_offset;
- area.y = FILL_Y(row);
- area.width = gui.num_cols * gui.char_width;
- area.height = gui.char_height;
-
- cr = cairo_create(gui.surface);
- cairo_rectangle(cr, area.x, area.y, area.width, area.height);
- cairo_clip(cr);
-
- glyphs = pango_glyph_string_new();
-
- // Fast path for pure ASCII: use cached glyph table.
- // Skip this path when force_pango is set (ligatures need shaping).
- if (!(flags & DRAW_ITALIC)
- && !((flags & DRAW_BOLD) && gui.font_can_bold)
- && gui.ascii_glyphs != NULL
- && !force_pango)
- {
- char_u *p;
-
- for (p = s; p < s + len; ++p)
- if (*p & 0x80)
- goto not_ascii;
-
- pango_glyph_string_set_size(glyphs, len);
-
- for (i = 0; i < len; ++i)
- {
- glyphs->glyphs[i] = gui.ascii_glyphs->glyphs[2 * s[i]];
- glyphs->log_clusters[i] = i;
- }
-
- draw_glyph_string(row, col, len, flags, gui.ascii_font, glyphs, cr);
-
- column_offset = len;
- }
- else
- {
-not_ascii:;
- PangoAttrList *attr_list;
- GList *item_list;
- int cluster_width;
- int last_glyph_rbearing;
- int cells = 0;
-
- // Safety check: pango crashes with invalid utf-8.
- if (!utf_valid_string(s, s + len))
- {
- column_offset = len;
- goto skipitall;
- }
-
- cluster_width = PANGO_SCALE * gui.char_width;
- last_glyph_rbearing = PANGO_SCALE * gui.char_width;
-
- attr_list = pango_attr_list_new();
-
- // If 'guifontwide' is set then use that for double-width characters.
- if (gui.wide_font != NULL)
- apply_wide_font_attr(s, len, attr_list);
-
- if ((flags & DRAW_BOLD) && gui.font_can_bold)
- INSERT_PANGO_ATTR(pango_attr_weight_new(PANGO_WEIGHT_BOLD),
- attr_list, 0, len);
- if (flags & DRAW_ITALIC)
- INSERT_PANGO_ATTR(pango_attr_style_new(PANGO_STYLE_ITALIC),
- attr_list, 0, len);
-
- item_list = pango_itemize(gui.text_context,
- (const char *)s, 0, len, attr_list, NULL);
-
- while (item_list != NULL)
- {
- PangoItem *item;
- int item_cells = 0;
-
- item = (PangoItem *)item_list->data;
- item_list = g_list_delete_link(item_list, item_list);
-
- // Force LTR direction; Vim handles bidi on its own.
- item->analysis.level = (item->analysis.level + 1) & (~1U);
-
- pango_shape_full((const char *)s + item->offset, item->length,
- (const char *)s, len, &item->analysis, glyphs);
-
- // Fixed-width hack: assign a fixed width to each glyph based on
- // the number of cells it occupies, handling composing characters
- // and cluster boundaries properly.
- for (i = 0; i < glyphs->num_glyphs; ++i)
- {
- PangoGlyphInfo *glyph;
-
- glyph = &glyphs->glyphs[i];
-
- if (glyph->attr.is_cluster_start)
- {
- int cellcount;
-
- cellcount = count_cluster_cells(
- s, item, glyphs, i, &cluster_width,
- (item_list != NULL) ? &last_glyph_rbearing : NULL);
-
- if (cellcount > 0)
- {
- int width;
-
- width = cellcount * gui.char_width * PANGO_SCALE;
- glyph->geometry.x_offset +=
- MAX(0, width - cluster_width) / 2;
- glyph->geometry.width = width;
- }
- else
- {
- setup_zero_width_cluster(item, glyph, cells,
- cluster_width,
- last_glyph_rbearing);
- }
-
- item_cells += cellcount;
- cells = cellcount;
- }
- else if (i > 0)
- {
- int width;
-
- if (glyph->geometry.x_offset >= 0)
- {
- glyphs->glyphs[i].geometry.width =
- glyphs->glyphs[i - 1].geometry.width;
- glyphs->glyphs[i - 1].geometry.width = 0;
- }
- width = cells * gui.char_width * PANGO_SCALE;
- glyph->geometry.x_offset +=
- MAX(0, width - cluster_width) / 2;
- }
- else
- {
- glyph->geometry.width = 0;
- }
- }
-
- draw_glyph_string(row, col + column_offset, item_cells,
- flags, item->analysis.font, glyphs, cr);
-
- pango_item_free(item);
-
- column_offset += item_cells;
- }
-
- pango_attr_list_unref(attr_list);
- }
-
-skipitall:
- draw_under(flags, row, col, column_offset, cr);
- cairo_destroy(cr);
-
- pango_glyph_string_free(glyphs);
-
- if (gui.drawarea != NULL)
- gtk_widget_queue_draw(gui.drawarea);
-
- return column_offset;
-}
-#endif // !USE_GTK4_SNAPSHOT
-
/*
* Draw a string of characters on the screen using the current font and colors.
* Splits the string into ASCII and ligature/UTF-8 segments so that ligature
@@ -3965,7 +3146,6 @@ skipitall:
int
gui_gtk_draw_string(int row, int col, char_u *s, int len, int flags)
{
-#ifdef USE_GTK4_SNAPSHOT
int cells;

cells = vim_draw_area_draw_string(VIM_DRAW_AREA(gui.drawarea),
@@ -3975,120 +3155,6 @@ gui_gtk_draw_string(int row, int col, char_u *s, int len, int flags)
gtk_widget_queue_draw(gui.drawarea);

return cells;
-#else
- char_u *conv_buf = NULL;
- int convlen;
- int len_sum;
- int byte_sum;
- char_u *cs;
- int needs_pango;
- int should_need_pango = FALSE;
- int slen;
- int is_ligature;
- int is_utf8;
- char_u backup_ch;
-
- if (gui.text_context == NULL || gui.surface == NULL)
- return len;
-
- if (output_conv.vc_type != CONV_NONE)
- {
- convlen = len;
- conv_buf = string_convert(&output_conv, s, &convlen);
- if (conv_buf != NULL)
- {
- s = conv_buf;
- len = convlen;
- }
- }
-
- /*
- * Ligature support:
- * Split the string into segments that are either pure ASCII (fast path)
- * or ligature/UTF-8 (Pango path). A single ligature character between
- * ASCII characters is treated as ASCII since it can't form a ligature
- * on its own.
- */
- len_sum = 0;
- byte_sum = 0;
- cs = s;
-
- // First char decides starting mode.
- is_utf8 = (*cs & 0x80);
- is_ligature = gui.ligatures_map[*cs] && (len > 1);
- if (is_ligature)
- is_ligature = gui.ligatures_map[*(cs + 1)];
- if (!is_utf8 && len > 1)
- is_utf8 = (*(cs + 1) & 0x80) != 0;
- needs_pango = is_utf8 || is_ligature;
-
- while (cs < s + len)
- {
- slen = 0;
- while (slen < (len - byte_sum))
- {
- is_ligature = gui.ligatures_map[*(cs + slen)];
- // Look ahead: single ligature char between ASCII is ASCII.
- if (is_ligature && !needs_pango)
- {
- if ((slen + 1) < (len - byte_sum))
- is_ligature = gui.ligatures_map[*(cs + slen + 1)];
- else
- is_ligature = 0;
- }
- is_utf8 = *(cs + slen) & 0x80;
- // ASCII followed by UTF-8 could be combining.
- if ((!is_utf8) && ((slen + 1) < (len - byte_sum)))
- is_utf8 = (*(cs + slen + 1) & 0x80);
- should_need_pango = (is_ligature || is_utf8);
- if (needs_pango != should_need_pango)
- break;
- if (needs_pango)
- {
- if (is_ligature)
- {
- slen++;
- }
- else
- {
- if ((*(cs + slen) & 0xC0) == 0x80)
- {
- while ((slen < (len - byte_sum))
- && ((*(cs + slen) & 0xC0) == 0x80))
- slen++;
- }
- else if ((*(cs + slen) & 0xE0) == 0xC0)
- slen++;
- else if ((*(cs + slen) & 0xF0) == 0xE0)
- slen += 2;
- else if ((*(cs + slen) & 0xF8) == 0xF0)
- slen += 3;
- else
- slen++;
- }
- }
- else
- {
- slen++;
- }
- }
-
- if (slen < len)
- {
- backup_ch = *(cs + slen);
- *(cs + slen) = NUL;
- }
- len_sum += gui_gtk_draw_string_ext(row, col + len_sum, cs, slen,
- flags, needs_pango);
- if (slen < len)
- *(cs + slen) = backup_ch;
- cs += slen;
- byte_sum += slen;
- needs_pango = should_need_pango;
- }
- vim_free(conv_buf);
- return len_sum;
-#endif
}

int
@@ -5012,7 +4078,6 @@ gui_mch_set_text_area_pos(int x, int y, int w, int h)
vim_form_move_resize(VIM_FORM(gui.formwin), gui.drawarea, x, y, w, h);
}

-#ifdef USE_GTK4_SNAPSHOT
/*
* Calculate the number of pixels to bleed background color to. Should be called
* after all UI elements are positioned and resized.
@@ -5043,7 +4108,6 @@ gui_gtk4_calculate_bleed(int width, int height)
if (old_right != gui.bleed_right || old_bot != gui.bleed_bot)
gtk_widget_queue_draw(GTK_WIDGET(gui.drawarea));
}
-#endif

/*
* ============================================================
diff --git a/src/gui_gtk4_da.c b/src/gui_gtk4_da.c
index 7a082cedf..80d3044cb 100644
--- a/src/gui_gtk4_da.c
+++ b/src/gui_gtk4_da.c
@@ -9,8 +9,6 @@

#include "vim.h"

-#ifdef USE_GTK4_SNAPSHOT
-
#include <gtk/gtk.h>
#include "gui_gtk4_da.h"

@@ -2024,5 +2022,3 @@ vim_draw_area_snapshot(GtkWidget *widget, GtkSnapshot *snapshot)
}
#endif
}
-
-#endif // USE_GTK4_SNAPSHOT
diff --git a/src/gui_gtk4_da.h b/src/gui_gtk4_da.h
index a214729a8..5708849f9 100644
--- a/src/gui_gtk4_da.h
+++ b/src/gui_gtk4_da.h
@@ -12,11 +12,9 @@

#include "vim.h"

-#ifdef USE_GTK4_SNAPSHOT
+#include <gtk/gtk.h>

-# include <gtk/gtk.h>
-
-# define VIM_TYPE_DRAW_AREA (vim_draw_area_get_type())
+#define VIM_TYPE_DRAW_AREA (vim_draw_area_get_type())
G_DECLARE_FINAL_TYPE(VimDrawArea, vim_draw_area, VIM, DRAW_AREA, GtkWidget)

GtkWidget *vim_draw_area_new(void);
@@ -27,17 +25,15 @@ void vim_draw_area_clear(VimDrawArea *self);
void vim_draw_area_move_block(VimDrawArea *self, int to, int row1, int row2, int col1, int col2);
void vim_draw_area_set_cursor(VimDrawArea *self, int w, int h);
void vim_draw_area_invert_block(VimDrawArea *self, int row, int col, int nrows, int ncols);
-# if defined(FEAT_SIGN_ICONS)
+#if defined(FEAT_SIGN_ICONS)
void vim_draw_area_add_sign(VimDrawArea *self, GdkTexture *sign, int row, int col, int width, int height);
-# endif
-# ifdef FEAT_NETBEANS_INTG
+#endif
+#ifdef FEAT_NETBEANS_INTG
void vim_draw_area_add_multisign(VimDrawArea *self, cairo_surface_t *surf, int row, int col, int width, int height);
-# endif
-# ifdef FEAT_IMAGE_GDK
+#endif
+#ifdef FEAT_IMAGE_GDK
void vim_draw_area_add_image(VimDrawArea *self, GdkTexture *image, int row, int col, double src_x, double src_y, double draw_w, double draw_h, int zindex, int id);
void vim_draw_area_remove_image(VimDrawArea *self, int id);
-# endif
-
#endif

#endif
diff --git a/src/netbeans.c b/src/netbeans.c
index abe5d11bc..9aec66490 100644
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -3100,7 +3100,7 @@ netbeans_draw_multisign_indicator(int row)
# else
GdkDrawable *drawable = gui.drawarea->window;
# endif
-# ifdef USE_GTK4_SNAPSHOT
+# ifdef USE_GTK4
cairo_surface_t *surf;
# endif

@@ -3108,14 +3108,14 @@ netbeans_draw_multisign_indicator(int row)
return;

x = 0;
-# ifdef USE_GTK4_SNAPSHOT
+# ifdef USE_GTK4
y = 2;
# else
y = row * gui.char_height + 2;
# endif

# if GTK_CHECK_VERSION(3,0,0)
-# ifdef USE_GTK4_SNAPSHOT
+# ifdef USE_GTK4
surf = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, 5, gui.char_height);
cr = cairo_create(surf);
@@ -3152,7 +3152,7 @@ netbeans_draw_multisign_indicator(int row)
gdk_draw_point(drawable, gui.text_gc, x+2, y);
# endif

-# ifdef USE_GTK4_SNAPSHOT
+# ifdef USE_GTK4
cairo_fill(cr);
gui_gtk4_add_multisign(surf, row, 0, 5, gui.char_height);
# endif
@@ -3160,7 +3160,7 @@ netbeans_draw_multisign_indicator(int row)
# if GTK_CHECK_VERSION(3,0,0)
cairo_destroy(cr);
# endif
-# ifdef USE_GTK4_SNAPSHOT
+# ifdef USE_GTK4
cairo_surface_destroy(surf);
# endif
}
diff --git a/src/po/vim.pot b/src/po/vim.pot
index 358f4bb61..b6ded2132 100644
--- a/src/po/vim.pot
+++ b/src/po/vim.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim
"
"Report-Msgid-Bugs-To: vim...@vim.org
"
-"POT-Creation-Date: 2026-07-23 20:13+0000
"
+"POT-Creation-Date: 2026-07-27 20:48+0000
"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>
"
"Language-Team: LANGUAGE <L...@li.org>
"
@@ -3469,9 +3469,6 @@ msgstr ""
msgid "without GUI."
msgstr ""

-msgid "with GTK4 GUI (hwaccel)."
-msgstr ""
-
msgid "with GTK4 GUI."
msgstr ""

diff --git a/src/proto/gui_gtk4.pro b/src/proto/gui_gtk4.pro
index 1541e4564..3c5f7a925 100644
--- a/src/proto/gui_gtk4.pro
+++ b/src/proto/gui_gtk4.pro
@@ -49,11 +49,8 @@ void gui_mch_draw_popup_image(win_T *wp, int row, int col, int src_x, int src_y,
void gui_mch_delete_lines(int row, int num_lines);
void gui_mch_insert_lines(int row, int num_lines);
void gui_gtk4_draw_cursor(guicolor_T bg, guicolor_T fg, int w, int h);
-void gui_mch_draw_hollow_cursor(guicolor_T color);
-void gui_mch_draw_part_cursor(int w, int h, guicolor_T color);
void gui_mch_flash(int msec);
void gui_mch_invert_rectangle(int r, int c, int nr, int nc);
-void gui_gtk4_resize(int width, int height);
void gui_gtk_set_dnd_targets(void);
void gui_mch_update(void);
int gui_mch_wait_for_chars(long wtime);
@@ -78,7 +75,6 @@ void gui_mch_set_curtab(int nr);
void gui_mch_drawsign(int row, int col, int typenr);
void *gui_mch_register_sign(char_u *signfile);
void gui_mch_destroy_sign(void *sign);
-int gui_gtk_draw_string_ext(int row, int col, char_u *s, int len, int flags, int force_pango);
int gui_gtk_draw_string(int row, int col, char_u *s, int len, int flags);
int gui_get_x11_windis(Window *win, Display **dis);
void gui_gtk_set_mnemonics(int enable);
diff --git a/src/version.c b/src/version.c
index 692175247..3f239da85 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 865,
/**/
864,
/**/
@@ -2835,11 +2837,7 @@ list_version(void)
msg_puts(_("without GUI."));
#elif defined(FEAT_GUI_GTK)
# if defined(USE_GTK4)
-# ifdef USE_GTK4_SNAPSHOT
- msg_puts(_("with GTK4 GUI (hwaccel)."));
-# else
msg_puts(_("with GTK4 GUI."));
-# endif
# elif defined(USE_GTK3)
msg_puts(_("with GTK3 GUI."));
# elif defined(FEAT_GUI_GNOME)
Reply all
Reply to author
Forward
0 new messages