From 1ebca75a89deb456da8f39a0804cb021f72c955e Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Sun, 20 Apr 2025 11:08:59 +0100 Subject: [PATCH] GTK: make inst->pixmap and inst->surface mutually exclusive This removes the case where we draw into a Cairo surface and then copy the results into a GdkPixmap. Now, if we've got a GdkPixmap, we just draw into it directly using Cairo. This vastly reduces the number of CopyArea operations needed to draw on the screen. --- unix/unifont.h | 6 ++++-- unix/window.c | 47 +++++++++++++---------------------------------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/unix/unifont.h b/unix/unifont.h index 6e22c257..687bfab3 100644 --- a/unix/unifont.h +++ b/unix/unifont.h @@ -40,8 +40,10 @@ * very simple rectangle-copy operation rather than a lot of fiddly * drawing or bitmap transfer. * - * However, GTK is deprecating the use of server-side pixmaps, so we - * have to disable this mode under some circumstances. + * For preference, we use a GdkPixmap for this, because both GDK and + * Cairo can draw to one of those. If those aren't available, then we + * instead create a Cairo surface that we hope will be backed by an X + * Pixmap. */ #define NO_BACKING_PIXMAPS #endif diff --git a/unix/window.c b/unix/window.c index bbaaa854..6454b1e9 100644 --- a/unix/window.c +++ b/unix/window.c @@ -108,21 +108,11 @@ struct GtkFrontend { * re-blit an appropriate rectangle from this pixmap. */ GdkPixmap *pixmap; -#endif -#ifdef DRAW_TEXT_CAIRO +#else /* - * If we're drawing using Cairo, we cache the same image on the - * client side in a Cairo surface. - * - * In GTK2+Cairo, this happens _as well_ as having the server-side - * pixmap cache above; in GTK3+Cairo, server-side pixmaps are - * deprecated, so we _just_ have this client-side cache. In the - * latter case that means we have to transmit a big wodge of - * bitmap data over the X connection on every expose event; but - * GTK3 apparently deliberately provides no way to avoid that - * inefficiency, and at least this way we don't _also_ have to - * redo any font rendering just because the window was temporarily - * covered. + * If we're avoiding GdkPixmaps, we cache the same image in a + * Cairo surface. Under X11, that surface will probably be a + * server-side pixmap. */ cairo_surface_t *surface; #endif @@ -811,9 +801,7 @@ static void drawing_area_setup(GtkFrontend *inst, int width, int height) inst->pixmap = gdk_pixmap_new(gtk_widget_get_window(inst->area), inst->backing_w, inst->backing_h, -1); -#endif - -#ifdef DRAW_TEXT_CAIRO +#else if (inst->surface) { cairo_surface_destroy(inst->surface); inst->surface = NULL; @@ -3592,10 +3580,15 @@ static bool gtkwin_setup_draw_ctx(TermWin *tw) #ifdef DRAW_TEXT_CAIRO if (inst->uctx.type == DRAWTYPE_CAIRO) { inst->uctx.u.cairo.widget = GTK_WIDGET(inst->area); - /* If we're doing Cairo drawing, we expect inst->surface to - * exist, and we draw to that first, regardless of whether we - * subsequently copy the results to inst->pixmap. */ + /* + * If we're doing Cairo drawing, we draw to the target pixmap + * if there is one, and otherwise to the backing surface. + */ +#ifdef NO_BACKING_PIXMAPS inst->uctx.u.cairo.cr = cairo_create(inst->surface); +#else + inst->uctx.u.cairo.cr = gdk_cairo_create(inst->pixmap); +#endif cairo_scale(inst->uctx.u.cairo.cr, inst->scale, inst->scale); cairo_setup_draw_ctx(inst); } @@ -3621,20 +3614,6 @@ static void gtkwin_free_draw_ctx(TermWin *tw) static void draw_update(GtkFrontend *inst, int x, int y, int w, int h) { -#if defined DRAW_TEXT_CAIRO && !defined NO_BACKING_PIXMAPS - if (inst->uctx.type == DRAWTYPE_CAIRO) { - /* - * If inst->surface and inst->pixmap both exist, then we've - * just drawn new content to the former which we must copy to - * the latter. - */ - cairo_t *cr = gdk_cairo_create(inst->pixmap); - cairo_set_source_surface(cr, inst->surface, 0, 0); - cairo_rectangle(cr, x, y, w, h); - cairo_fill(cr); - cairo_destroy(cr); - } -#endif /* * Now we just queue a window redraw, which will cause