- Updated main GUI color helpers and tab palette generation to use XTextColor, and simplified drag icon snapshotting to use gdk_pixbuf_get_from_window with a null guard.

- Added pixbuf-based cairo surface capture for xtext window scrolling with a fallback to full redraw when capture fails.
This commit is contained in:
2026-01-17 21:56:00 -07:00
parent 4ac836fc66
commit c1f855c2ab
2 changed files with 134 additions and 84 deletions

View File

@@ -59,6 +59,7 @@
#else
#include <unistd.h>
#include <gdk/gdkcairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
@@ -157,13 +158,89 @@ xtext_set_source_color (cairo_t *cr, const XTextColor *color, gdouble alpha)
color->blue, color->alpha * alpha);
}
static cairo_surface_t *
xtext_surface_from_pixbuf (GdkPixbuf *pixbuf)
{
cairo_surface_t *surface;
gboolean has_alpha;
int width;
int height;
int src_stride;
int dest_stride;
int n_channels;
const guchar *src_pixels;
unsigned char *dest_pixels;
int x;
int y;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
return NULL;
}
src_stride = gdk_pixbuf_get_rowstride (pixbuf);
src_pixels = gdk_pixbuf_get_pixels (pixbuf);
dest_stride = cairo_image_surface_get_stride (surface);
dest_pixels = cairo_image_surface_get_data (surface);
for (y = 0; y < height; y++)
{
const guchar *src_row = src_pixels + (y * src_stride);
guint32 *dest_row = (guint32 *)(dest_pixels + (y * dest_stride));
for (x = 0; x < width; x++)
{
const guchar *src = src_row + (x * n_channels);
guchar alpha = has_alpha ? src[3] : 0xff;
guchar red = src[0];
guchar green = src[1];
guchar blue = src[2];
guchar premul_red = (guchar)((red * alpha + 127) / 255);
guchar premul_green = (guchar)((green * alpha + 127) / 255);
guchar premul_blue = (guchar)((blue * alpha + 127) / 255);
dest_row[x] = ((guint32)alpha << 24) |
((guint32)premul_red << 16) |
((guint32)premul_green << 8) |
((guint32)premul_blue);
}
}
cairo_surface_mark_dirty (surface);
return surface;
}
static cairo_surface_t *
xtext_surface_from_window (GdkWindow *window)
{
cairo_t *cr = gdk_cairo_create (window);
cairo_surface_t *surface = cairo_surface_reference (cairo_get_target (cr));
cairo_surface_t *surface = NULL;
GdkPixbuf *pixbuf;
GdkDrawable *drawable;
int width;
int height;
cairo_destroy (cr);
drawable = GDK_DRAWABLE (window);
if (!drawable)
return NULL;
gdk_drawable_get_size (drawable, &width, &height);
pixbuf = gdk_pixbuf_get_from_drawable (NULL, drawable, NULL,
0, 0, 0, 0, width, height);
if (pixbuf)
{
surface = xtext_surface_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
}
return surface;
}
@@ -3873,6 +3950,12 @@ gtk_xtext_render_page (GtkXText * xtext)
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window);
if (!surface)
{
cairo_restore (cr);
cairo_destroy (cr);
goto full_redraw;
}
cairo_set_source_surface (cr, surface, dest_x - src_x, dest_y - src_y);
cairo_surface_destroy (surface);
cairo_rectangle (cr, dest_x, dest_y, width, copy_height);
@@ -3894,6 +3977,12 @@ gtk_xtext_render_page (GtkXText * xtext)
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window);
if (!surface)
{
cairo_restore (cr);
cairo_destroy (cr);
goto full_redraw;
}
cairo_set_source_surface (cr, surface, dest_x - src_x, dest_y - src_y);
cairo_surface_destroy (surface);
cairo_rectangle (cr, dest_x, dest_y, width, copy_height);
@@ -3915,6 +4004,7 @@ gtk_xtext_render_page (GtkXText * xtext)
}
#endif
full_redraw:
width -= MARGIN;
lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + 1;