From 2ac523480381cf4a88527aeb998f696669f78036 Mon Sep 17 00:00:00 2001 From: deepend Date: Sat, 17 Jan 2026 17:34:38 -0700 Subject: [PATCH] - Added Cairo-based window snapshot conversion (with unpremultiplication) for drag icons and updated drag rendering to use the new helper instead of drawable capture. - Updated GtkXText to track the draw window and use a pixmap-to-surface helper for Cairo contexts, avoiding drawable references in the struct and rendering flow. - Added a Cairo helper for capturing window-backed surfaces and used it when blitting during scrolling, fixing the build break from the removed drawable helper. --- src/fe-gtk/maingui.c | 104 ++++++++++++++++++++++++++++++++++++++----- src/fe-gtk/xtext.c | 26 ++++++++--- src/fe-gtk/xtext.h | 2 +- 3 files changed, 113 insertions(+), 19 deletions(-) diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 3bbc7824..5b633007 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -91,6 +91,88 @@ mg_set_source_color (cairo_t *cr, const GdkColor *color) color->blue / 65535.0, 1.0); } +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define MG_CAIRO_BLUE 0 +#define MG_CAIRO_GREEN 1 +#define MG_CAIRO_RED 2 +#define MG_CAIRO_ALPHA 3 +#else +#define MG_CAIRO_ALPHA 0 +#define MG_CAIRO_RED 1 +#define MG_CAIRO_GREEN 2 +#define MG_CAIRO_BLUE 3 +#endif + +static inline void +mg_unpremultiply_pixel (const guchar *src, guchar *dest) +{ + guchar alpha = src[MG_CAIRO_ALPHA]; + guchar red = src[MG_CAIRO_RED]; + guchar green = src[MG_CAIRO_GREEN]; + guchar blue = src[MG_CAIRO_BLUE]; + + if (alpha == 0) + { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + return; + } + + dest[0] = (guchar)((red * 255 + alpha / 2) / alpha); + dest[1] = (guchar)((green * 255 + alpha / 2) / alpha); + dest[2] = (guchar)((blue * 255 + alpha / 2) / alpha); + dest[3] = alpha; +} + +static GdkPixbuf * +mg_pixbuf_from_window (GdkWindow *window, int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr; + GdkPixbuf *pixbuf; + guchar *surface_data; + guchar *dest; + int surface_stride; + int dest_stride; + int x; + int y; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + gdk_cairo_set_source_window (cr, window, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_surface_flush (surface); + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + surface_data = cairo_image_surface_get_data (surface); + surface_stride = cairo_image_surface_get_stride (surface); + dest = gdk_pixbuf_get_pixels (pixbuf); + dest_stride = gdk_pixbuf_get_rowstride (pixbuf); + + for (y = 0; y < height; y++) + { + const guchar *src_row = surface_data + (y * surface_stride); + guchar *dest_row = dest + (y * dest_stride); + + for (x = 0; x < width; x++) + { + const guchar *src = src_row + (x * 4); + guchar *dst = dest_row + (x * 4); + + mg_unpremultiply_pixel (src, dst); + } + } + + cairo_surface_destroy (surface); + + return pixbuf; +} + static void mg_create_entry (session *sess, GtkWidget *box); static void mg_create_search (session *sess, GtkWidget *box); #ifdef G_OS_WIN32 @@ -4062,18 +4144,18 @@ gboolean mg_drag_begin_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata) { int width, height; - GdkColormap *cmap; GdkPixbuf *pix, *pix2; + GdkWindow *window; /* ignore file drops */ if (!mg_is_gui_target (context)) return FALSE; - cmap = gtk_widget_get_colormap (widget); - width = gdk_window_get_width (gtk_widget_get_window (widget)); - height = gdk_window_get_height (gtk_widget_get_window (widget)); + window = gtk_widget_get_window (widget); + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); - pix = gdk_pixbuf_get_from_drawable (NULL, gtk_widget_get_window (widget), cmap, 0, 0, 0, 0, width, height); + pix = mg_pixbuf_from_window (window, width, height); pix2 = gdk_pixbuf_scale_simple (pix, width * 4 / 5, height / 2, GDK_INTERP_HYPER); g_object_unref (pix); @@ -4128,7 +4210,7 @@ mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, gui cairo_t *cr; int half, width, height; int ox, oy; - GdkDrawable *draw; + GdkWindow *window; GtkAllocation allocation; /* ignore file drops */ @@ -4142,20 +4224,20 @@ mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, gui oy = allocation.y; width = allocation.width; height = allocation.height; - draw = gtk_widget_get_window (widget); + window = gtk_widget_get_window (widget); } else { ox = oy = 0; - width = gdk_window_get_width (gtk_widget_get_window (widget)); - height = gdk_window_get_height (gtk_widget_get_window (widget)); - draw = gtk_widget_get_window (widget); + window = gtk_widget_get_window (widget); + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); } col.red = rand() % 0xffff; col.green = rand() % 0xffff; col.blue = rand() % 0xffff; - cr = gdk_cairo_create (draw); + cr = gdk_cairo_create (window); cairo_set_operator (cr, CAIRO_OPERATOR_XOR); mg_set_source_color (cr, &col); cairo_set_line_width (cr, 1.0); diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index ba76699c..fe57789c 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -158,9 +158,20 @@ xtext_set_source_color (cairo_t *cr, GdkColor *color, gdouble alpha) } static cairo_surface_t * -xtext_surface_from_drawable (GdkDrawable *drawable) +xtext_surface_from_pixmap (GdkPixmap *pixmap) { - cairo_t *cr = gdk_cairo_create (drawable); + cairo_t *cr = gdk_cairo_create (pixmap); + cairo_surface_t *surface = cairo_surface_reference (cairo_get_target (cr)); + + cairo_destroy (cr); + + 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_destroy (cr); @@ -174,7 +185,7 @@ xtext_create_context (GtkXText *xtext) if (xtext->draw_surface) return cairo_create (xtext->draw_surface); - return gdk_cairo_create (xtext->draw_buf); + return gdk_cairo_create (xtext->draw_window); } static inline void @@ -215,7 +226,7 @@ xtext_draw_bg_offset (GtkXText *xtext, int x, int y, int width, int height, int if (xtext->pixmap) { - cairo_surface_t *surface = xtext_surface_from_drawable (xtext->pixmap); + cairo_surface_t *surface = xtext_surface_from_pixmap (xtext->pixmap); cairo_set_source_surface (cr, surface, tile_x, tile_y); cairo_surface_destroy (surface); @@ -487,6 +498,7 @@ static void gtk_xtext_init (GtkXText * xtext) { xtext->pixmap = NULL; + xtext->draw_window = NULL; xtext->draw_surface = NULL; xtext->io_tag = 0; xtext->add_io_tag = 0; @@ -758,7 +770,7 @@ gtk_xtext_realize (GtkWidget * widget) xtext_set_bg (xtext, XTEXT_BG); /* draw directly to window */ - xtext->draw_buf = widget->window; + xtext->draw_window = widget->window; if (xtext->pixmap) { @@ -3877,7 +3889,7 @@ gtk_xtext_render_page (GtkXText * xtext) cr = xtext_create_context (xtext); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - surface = xtext_surface_from_drawable (GTK_WIDGET (xtext)->window); + surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window); 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); @@ -3898,7 +3910,7 @@ gtk_xtext_render_page (GtkXText * xtext) cr = xtext_create_context (xtext); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - surface = xtext_surface_from_drawable (GTK_WIDGET (xtext)->window); + surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window); 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); diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h index a2f18a13..83e00839 100644 --- a/src/fe-gtk/xtext.h +++ b/src/fe-gtk/xtext.h @@ -131,7 +131,7 @@ struct _GtkXText GtkAdjustment *adj; GdkPixmap *pixmap; /* 0 = use palette[19] */ - GdkDrawable *draw_buf; /* points to ->window */ + GdkWindow *draw_window; /* points to ->window */ cairo_surface_t *draw_surface; /* temporary surface for offscreen draws */ GdkCursor *hand_cursor; GdkCursor *resize_cursor;