From cf41615cb32d10907737e6743b00cb0a1c72d10f Mon Sep 17 00:00:00 2001 From: deepend Date: Sat, 17 Jan 2026 22:25:12 -0700 Subject: [PATCH] =?UTF-8?q?-=20Reworked=20GTK=20window=20snapshotting=20in?= =?UTF-8?q?=20the=20main=20GUI=20to=20capture=20into=20cairo=20surfaces=20?= =?UTF-8?q?and=20convert=20via=20gdk=5Fpixbuf=5Fget=5Ffrom=5Fsurface.=20-?= =?UTF-8?q?=20Added=20a=20Cairo=20surface=20=E2=86=92=20RGBA=20pixbuf=20co?= =?UTF-8?q?nversion=20helper=20that=20unpremultiplies=20ARGB32=20data=20fo?= =?UTF-8?q?r=20GTK2=20compatibility=20while=20keeping=20window=20snapshots?= =?UTF-8?q?=20Cairo-based.=20-=20Updated=20window=20snapshotting=20to=20us?= =?UTF-8?q?e=20the=20new=20Cairo=20surface=20conversion=20instead=20of=20g?= =?UTF-8?q?dk=5Fpixbuf=5Fget=5Ffrom=5Fsurface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/maingui.c | 103 ++++++++++++++++++++++++++++++++++++++++--- src/fe-gtk/xtext.c | 83 ++++++---------------------------- 2 files changed, 110 insertions(+), 76 deletions(-) diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 25ca42ee..31f92f26 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -102,26 +102,117 @@ mg_color_component_to_pango (double value) return (guint16)(value * 65535.0 + 0.5); } +static void +mg_pixbuf_destroy (guchar *pixels, gpointer data) +{ + g_free (pixels); +} + +static GdkPixbuf * +mg_pixbuf_from_surface (cairo_surface_t *surface, int width, int height) +{ + const unsigned char *src; + int src_stride; + int rowstride; + guchar *pixels; + int x; + int y; + + if (!surface || width <= 0 || height <= 0) + return NULL; + + src = cairo_image_surface_get_data (surface); + src_stride = cairo_image_surface_get_stride (surface); + rowstride = width * 4; + pixels = g_malloc ((gsize)rowstride * height); + + for (y = 0; y < height; y++) + { + const unsigned char *src_row = src + (y * src_stride); + guchar *dest_row = pixels + (y * rowstride); + + for (x = 0; x < width; x++) + { + guint8 a; + guint8 r; + guint8 g; + guint8 b; + const unsigned char *src_px = src_row + (x * 4); + guchar *dest_px = dest_row + (x * 4); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + b = src_px[0]; + g = src_px[1]; + r = src_px[2]; + a = src_px[3]; +#else + a = src_px[0]; + r = src_px[1]; + g = src_px[2]; + b = src_px[3]; +#endif + + if (a) + { + r = (guint8)((r * 255 + (a / 2)) / a); + g = (guint8)((g * 255 + (a / 2)) / a); + b = (guint8)((b * 255 + (a / 2)) / a); + } + else + { + r = g = b = 0; + } + + dest_px[0] = r; + dest_px[1] = g; + dest_px[2] = b; + dest_px[3] = a; + } + } + + return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, + width, height, rowstride, mg_pixbuf_destroy, NULL); +} + static GdkPixbuf * mg_pixbuf_from_window (GdkWindow *window, int width, int height) { - GdkDrawable *drawable; int src_width; int src_height; + cairo_surface_t *surface; + cairo_t *cr; + GdkPixbuf *pixbuf; - drawable = GDK_DRAWABLE (window); - if (!drawable) + if (!window) return NULL; - gdk_drawable_get_size (drawable, &src_width, &src_height); + src_width = gdk_window_get_width (window); + src_height = gdk_window_get_height (window); if (width <= 0 || height <= 0) { width = src_width; height = src_height; } - return gdk_pixbuf_get_from_drawable (NULL, drawable, NULL, - 0, 0, 0, 0, width, height); + if (width <= 0 || height <= 0) + return NULL; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) + { + cairo_surface_destroy (surface); + return NULL; + } + + cr = cairo_create (surface); + gdk_cairo_set_source_window (cr, window, 0.0, 0.0); + cairo_paint (cr); + cairo_destroy (cr); + + pixbuf = mg_pixbuf_from_surface (surface, width, height); + cairo_surface_destroy (surface); + + return pixbuf; } static void mg_create_entry (session *sess, GtkWidget *box); diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index 8094fa95..8f3cc190 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -59,7 +59,6 @@ #else #include #include -#include #ifdef GDK_WINDOWING_X11 #include #endif @@ -159,26 +158,20 @@ xtext_set_source_color (cairo_t *cr, const XTextColor *color, gdouble alpha) } static cairo_surface_t * -xtext_surface_from_pixbuf (GdkPixbuf *pixbuf) +xtext_surface_from_window (GdkWindow *window) { - cairo_surface_t *surface; - gboolean has_alpha; + cairo_surface_t *surface = NULL; 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; + cairo_t *cr; - g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); + if (!window) + return 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); + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); + if (width <= 0 || height <= 0) + return NULL; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) @@ -187,60 +180,10 @@ xtext_surface_from_pixbuf (GdkPixbuf *pixbuf) 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_surface_t *surface = NULL; - GdkPixbuf *pixbuf; - GdkDrawable *drawable; - int width; - int height; - - 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); - } + cr = cairo_create (surface); + gdk_cairo_set_source_window (cr, window, 0.0, 0.0); + cairo_paint (cr); + cairo_destroy (cr); return surface; }