Commit: patch 9.2.0897: GTK3 X11 redraws are not coalesced

Christian Brabandt <[email protected]> Sun, 2 Aug 2026 20:15:03 +0200
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0897: GTK3 X11 redraws are not coalesced

Commit: https://github.com/vim/vim/commit/cd29d79dde5a076a859009b97287e6357933efe3
Author: Christoffer Aasted <[email protected]>
Date:   Sun Aug 2 18:01:14 2026 +0000

    patch 9.2.0897: GTK3 X11 redraws are not coalesced
    
    Problem:  GTK3 X11 redraws are not coalesced
    Solution: Improve redrawing logic, unify Wayland with X11 redraw
              code (Christoffer Aasted)
    
    closes: #20909
    
    Signed-off-by: Christoffer Aasted <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c
index 0647d9b16..f2db6d1da 100644
--- a/src/gui_gtk_x11.c
+++ b/src/gui_gtk_x11.c
@@ -778,25 +778,7 @@ draw_event(GtkWidget *widget UNUSED,
 				// for GTK+ 3, may induce other draw events.
 
     cairo_set_source_surface(cr, gui.surface, 0, 0);
-
-    {
-	cairo_rectangle_list_t *list = NULL;
-
-	list = cairo_copy_clip_rectangle_list(cr);
-	if (list->status != CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
-	{
-	    int i;
-
-	    for (i = 0; i < list->num_rectangles; i++)
-	    {
-		const cairo_rectangle_t *rect = &list->rectangles[i];
-		cairo_rectangle(cr, rect->x, rect->y,
-						    rect->width, rect->height);
-		cairo_fill(cr);
-	    }
-	}
-	cairo_rectangle_list_destroy(list);
-    }
+    cairo_paint(cr);
 
     return FALSE;
 }
@@ -3758,54 +3740,6 @@ gui_gtk_set_dnd_targets(void)
 		      GDK_ACTION_COPY | GDK_ACTION_MOVE);
 }
 
-#ifdef GDK_WINDOWING_WAYLAND
-static struct {
-    int left;
-    int top;
-    int right;
-    int bottom;
-    bool active;
-} wl_dirty_rect = {0, 0, 0, 0, false};
-
-    static void
-wl_queue_dirty_area(int x, int y, int width, int height)
-{
-    if (!wl_dirty_rect.active)
-    {
-	wl_dirty_rect.left = x;
-	wl_dirty_rect.top = y;
-	wl_dirty_rect.right = x + width;
-	wl_dirty_rect.bottom = y + height;
-	wl_dirty_rect.active = true;
-    }
-    else
-    {
-	// Expand to append further changes
-	if (x < wl_dirty_rect.left)   wl_dirty_rect.left = x;
-	if (y < wl_dirty_rect.top)    wl_dirty_rect.top = y;
-	if (x + width > wl_dirty_rect.right)  wl_dirty_rect.right = x + width;
-	if (y + height > wl_dirty_rect.bottom) wl_dirty_rect.bottom = y + height;
-    }
-}
-
-    static void
-wl_flush(void)
-{
-    if (!wl_dirty_rect.active)
-	return;
-    int draw_x = wl_dirty_rect.left;
-    int draw_y = wl_dirty_rect.top;
-    int draw_w = wl_dirty_rect.right - wl_dirty_rect.left;
-    int draw_h = wl_dirty_rect.bottom - wl_dirty_rect.top;
-
-    if (draw_w > 0 && draw_h > 0)
-    {
-	gtk_widget_queue_draw_area(gui.drawarea, draw_x, draw_y, draw_w, draw_h);
-    }
-    wl_dirty_rect.active = false;
-}
-#endif
-
 /*
  * Initialize the GUI.	Create all the windows, set up all the callbacks etc.
  * Returns OK for success, FAIL when the GUI can't be started.
@@ -6287,20 +6221,28 @@ gui_gtk_draw_string(int row, int col, char_u *s, int len, int flags)
     return len_sum;
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+static cairo_region_t *dirty_region = NULL;
+
     static void
-queue_draw_area(
-	int	x,
-	int	y,
-	int	width,
-	int	height)
+queue_draw_area(int x, int y, int width, int height)
 {
-#ifdef GDK_WINDOWING_WAYLAND
-    if (gui.is_wayland)
-	wl_queue_dirty_area(x, y, width, height);
+    cairo_rectangle_int_t rect;
+
+    if (width <= 0 || height <= 0 || gui.drawarea == NULL)
+	return;
+
+    rect.x = x;
+    rect.y = y;
+    rect.width = width;
+    rect.height = height;
+
+    if (dirty_region == NULL)
+	dirty_region = cairo_region_create_rectangle(&rect);
     else
-#endif
-	gtk_widget_queue_draw_area(gui.drawarea, x, y, width, height);
+	cairo_region_union_rectangle(dirty_region, &rect);
 }
+#endif
 
     int
 gui_gtk_draw_string_ext(
@@ -6554,8 +6496,8 @@ skipitall:
 
 #if GTK_CHECK_VERSION(3,0,0)
     cairo_destroy(cr);
-    queue_draw_area(area.x, area.y,
-	    area.width, area.height);
+    queue_draw_area(FILL_X(col), FILL_Y(row),
+	    column_offset * gui.char_width + 1, gui.char_height);
 #else
     gdk_gc_set_clip_rectangle(gui.text_gc, NULL);
 #endif
@@ -6698,8 +6640,7 @@ gui_mch_invert_rectangle(int r, int c, int nr, int nc)
 
     cairo_destroy(cr);
 
-    queue_draw_area(rect.x, rect.y,
-	    rect.width, rect.height);
+    queue_draw_area(rect.x, rect.y, rect.width, rect.height);
 #else
     GdkGCValues values;
     GdkGC *invert_gc;
@@ -6852,17 +6793,14 @@ gui_mch_update(void)
 {
     int cnt = 0;	// prevent endless loop
     while (g_main_context_pending(NULL) && !vim_is_input_buf_full()
-								&& ++cnt < 100)
+	    && ++cnt < 100)
     {
-#ifdef GDK_WINDOWING_WAYLAND
-	if (gui.is_wayland)
-	{
-	    int prio = 0;
-	    g_main_context_prepare(NULL, &prio);
-	    // peek internal scheduling of redraw
-	    if (prio == GDK_PRIORITY_REDRAW)
-		gui_may_flush(); // prepares redraw: g_main_context_iteration
-	}
+#if GTK_CHECK_VERSION(3,0,0)
+	int prio = 0;
+	g_main_context_prepare(NULL, &prio);
+	// peek internal scheduling of redraw
+	if (prio == GDK_PRIORITY_REDRAW)
+	    gui_may_flush(); // prepares redraw: g_main_context_iteration
 #endif
 	g_main_context_iteration(NULL, TRUE);
     }
@@ -6997,18 +6935,19 @@ theend:
     void
 gui_mch_flush(void)
 {
-    if (gui.mainwin != NULL && gtk_widget_get_realized(gui.mainwin))
+    if (gui.mainwin == NULL || !gtk_widget_get_realized(gui.mainwin))
+	return;
+#if GTK_CHECK_VERSION(3,0,0)
+    if (dirty_region != NULL && gui.drawarea != NULL)
     {
-#ifdef GDK_WINDOWING_WAYLAND
-	if (gui.is_wayland)
-	    return wl_flush();
-#endif
-#if GTK_CHECK_VERSION(2,4,0)
-	gdk_display_flush(gtk_widget_get_display(gui.mainwin));
+	gtk_widget_queue_draw_region(gui.drawarea, dirty_region);
+	cairo_region_destroy(dirty_region);
+	dirty_region = NULL;
+    }
 #else
-	gdk_display_sync(gtk_widget_get_display(gui.mainwin));
+       gdk_display_flush(gtk_widget_get_display(gui.mainwin));
+       return;
 #endif
-    }
 }
 
 /*
@@ -7060,8 +6999,7 @@ gui_mch_clear_block(int row1arg, int col1arg, int row2arg, int col2arg)
 	cairo_fill(cr);
 	cairo_destroy(cr);
 
-	queue_draw_area(
-		rect.x, rect.y, rect.width, rect.height);
+	queue_draw_area(rect.x, rect.y, rect.width, rect.height);
     }
 #else // !GTK_CHECK_VERSION(3,0,0)
     gdk_gc_set_foreground(gui.text_gc, &color);
@@ -7097,8 +7035,7 @@ gui_gtk_window_clear(GdkWindow *win)
     cairo_fill(cr);
     cairo_destroy(cr);
 
-    queue_draw_area(
-	    rect.x, rect.y, rect.width, rect.height);
+    queue_draw_area(rect.x, rect.y, rect.width, rect.height);
 }
 #else
 # define gui_gtk_window_clear(win)  gdk_window_clear(win)
@@ -7156,8 +7093,7 @@ gui_mch_draw_popup_image(
 # if GTK_CHECK_VERSION(3,0,0)
     cairo_popup_image_paint(wp, gui.surface, x, y,
 	    src_x, src_y, draw_w, draw_h);
-    if (gui.drawarea != NULL)
-	queue_draw_area(x, y, draw_w, draw_h);
+    queue_draw_area(x, y, draw_w, draw_h);
 # else
     cairo_popup_image_paint(wp, gui.drawarea->window, x, y,
 	    src_x, src_y, draw_w, draw_h);
diff --git a/src/version.c b/src/version.c
index 30b9a310b..7c831d2ae 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 */
+/**/
+    897,
 /**/
     896,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wqaiF-009Yif-IK%40256bit.org.