patch 9.2.0505: GTK4: text looks blurry on HiDPI displays
Commit:
https://github.com/vim/vim/commit/aed758986de7e677d63b1f6caa845938a2fabbdc
Author: Yasuhiro Matsumoto <[email protected]>
Date: Wed May 20 18:26:14 2026 +0000
patch 9.2.0505: GTK4: text looks blurry on HiDPI displays
Problem: GTK4: text looks blurry on HiDPI displays
(Foxe Chen, after v9.2.0501)
Solution: Allocate the cairo surface at physical resolution and set the
device scale, recreate it on scale-factor changes
(Yasuhiro Matsumoto).
The backing cairo image surface was created at logical pixel size, so
GTK4 upscaled it when blitting to the physical framebuffer. Allocate
the surface at width*scale x height*scale and apply
cairo_surface_set_device_scale() so drawing code keeps using logical
coordinates while the surface itself has full physical resolution.
Also recreate the surface on notify::scale-factor when the window
moves between monitors with different scales.
fixes: #20252
closes: #20258
Co-authored-by: Claude <[email protected]>
Signed-off-by: Yasuhiro Matsumoto <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c
index 24ad6ddce..083ac9f40 100644
--- a/src/gui_gtk4.c
+++ b/src/gui_gtk4.c
@@ -290,6 +290,8 @@ static gboolean delete_event_cb(GtkWindow *window, gpointer
data);
static void drawarea_realize_cb(GtkWidget *widget, gpointer data);
static void drawarea_unrealize_cb(GtkWidget *widget, gpointer data);
static void drawarea_resize_cb(GtkDrawingArea *area, int width, int height,
gpointer data);
+static void drawarea_scale_factor_cb(GObject *object, GParamSpec *pspec,
gpointer data);
+static cairo_surface_t *create_backing_surface(int width, int height);
/*
* Parse the GUI related command-line arguments. Any arguments used are
@@ -523,6 +525,8 @@ gui_mch_init(void)
G_CALLBACK(drawarea_unrealize_cb), NULL);
g_signal_connect(G_OBJECT(gui.drawarea), "resize",
G_CALLBACK(drawarea_resize_cb), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "notify::scale-factor",
+ G_CALLBACK(drawarea_scale_factor_cb), NULL);
// Set up event controllers.
{
@@ -1302,6 +1306,34 @@ set_cairo_source_from_pixel(cairo_t *cr, guicolor_T
pixel)
(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;
+}
+
void
gui_mch_clear_block(int row1, int col1, int row2, int col2)
{
@@ -1352,7 +1384,9 @@ surface_copy_rect(int dest_x, int dest_y,
return;
// Use a temporary surface to avoid overlap issues
- tmp = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ 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);
@@ -1829,7 +1863,7 @@ drawarea_realize_cb(GtkWidget *widget UNUSED, gpointer
data UNUSED)
if (gui.surface != NULL)
cairo_surface_destroy(gui.surface);
- gui.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
+ gui.surface = create_backing_surface(w, h);
gui_mch_new_colors();
@@ -1853,14 +1887,15 @@ drawarea_resize_cb(GtkDrawingArea *area UNUSED, int
width, int height,
gpointer data UNUSED)
{
cairo_t *cr;
+ int scale = get_drawarea_scale();
if (width <= 0 || height <= 0)
return;
if (gui.surface != NULL)
{
- int sw = cairo_image_surface_get_width(gui.surface);
- int sh = cairo_image_surface_get_height(gui.surface);
+ 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)
return;
@@ -1872,8 +1907,7 @@ drawarea_resize_cb(GtkDrawingArea *area UNUSED, int
width, int height,
// Do not copy old surface content: gui_resize_shell() will trigger
// a full redraw, and stale content (e.g. intro screen text) would
// otherwise remain as ghost artifacts.
- gui.surface = cairo_image_surface_create(
- CAIRO_FORMAT_ARGB32, width, height);
+ gui.surface = create_backing_surface(width, height);
cr = cairo_create(gui.surface);
set_cairo_source_from_pixel(cr, gui.back_pixel);
cairo_paint(cr);
@@ -1883,6 +1917,36 @@ drawarea_resize_cb(GtkDrawingArea *area UNUSED, int
width, int height,
gui_resize_shell(width, height);
}
+ static void
+drawarea_scale_factor_cb(GObject *object UNUSED,
+ GParamSpec *pspec UNUSED, gpointer data UNUSED)
+{
+ int w, h;
+
+ if (gui.drawarea == NULL)
+ return;
+
+ 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);
+}
+
#ifdef FEAT_DND
/*
* Drag-and-drop handler for files and text.
@@ -3791,15 +3855,17 @@ gui_mch_set_text_area_pos(int x, int y, int w, int h)
// Update surface to match new text area size
if (w > 0 && h > 0)
{
+ int scale = get_drawarea_scale();
+
if (gui.surface != NULL)
{
- int sw = cairo_image_surface_get_width(gui.surface);
- int sh = cairo_image_surface_get_height(gui.surface);
+ int sw = cairo_image_surface_get_width(gui.surface) / scale;
+ int sh = cairo_image_surface_get_height(gui.surface) / scale;
if (sw == w && sh == h)
return;
cairo_surface_destroy(gui.surface);
}
- gui.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
+ gui.surface = create_backing_surface(w, h);
}
}
diff --git a/src/version.c b/src/version.c
index e07f50f04..f46d48acc 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 505,
/**/
504,
/**/
--
--
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/E1wPlui-00F8I1-Ou%40256bit.org.