mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-19 04:00:19 +00:00
- Reworked GTK window snapshotting in the main GUI to capture into cairo surfaces and convert via gdk_pixbuf_get_from_surface.
- Added a Cairo surface → RGBA pixbuf conversion helper that unpremultiplies ARGB32 data for GTK2 compatibility while keeping window snapshots Cairo-based. - Updated window snapshotting to use the new Cairo surface conversion instead of gdk_pixbuf_get_from_surface
This commit is contained in:
@@ -102,26 +102,117 @@ mg_color_component_to_pango (double value)
|
|||||||
return (guint16)(value * 65535.0 + 0.5);
|
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 *
|
static GdkPixbuf *
|
||||||
mg_pixbuf_from_window (GdkWindow *window, int width, int height)
|
mg_pixbuf_from_window (GdkWindow *window, int width, int height)
|
||||||
{
|
{
|
||||||
GdkDrawable *drawable;
|
|
||||||
int src_width;
|
int src_width;
|
||||||
int src_height;
|
int src_height;
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
cairo_t *cr;
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
|
||||||
drawable = GDK_DRAWABLE (window);
|
if (!window)
|
||||||
if (!drawable)
|
|
||||||
return NULL;
|
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)
|
if (width <= 0 || height <= 0)
|
||||||
{
|
{
|
||||||
width = src_width;
|
width = src_width;
|
||||||
height = src_height;
|
height = src_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
return gdk_pixbuf_get_from_drawable (NULL, drawable, NULL,
|
if (width <= 0 || height <= 0)
|
||||||
0, 0, 0, 0, width, height);
|
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);
|
static void mg_create_entry (session *sess, GtkWidget *box);
|
||||||
|
|||||||
@@ -59,7 +59,6 @@
|
|||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <gdk/gdkcairo.h>
|
#include <gdk/gdkcairo.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -159,26 +158,20 @@ xtext_set_source_color (cairo_t *cr, const XTextColor *color, gdouble alpha)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static cairo_surface_t *
|
static cairo_surface_t *
|
||||||
xtext_surface_from_pixbuf (GdkPixbuf *pixbuf)
|
xtext_surface_from_window (GdkWindow *window)
|
||||||
{
|
{
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface = NULL;
|
||||||
gboolean has_alpha;
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int src_stride;
|
cairo_t *cr;
|
||||||
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);
|
if (!window)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
width = gdk_pixbuf_get_width (pixbuf);
|
width = gdk_window_get_width (window);
|
||||||
height = gdk_pixbuf_get_height (pixbuf);
|
height = gdk_window_get_height (window);
|
||||||
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
if (width <= 0 || height <= 0)
|
||||||
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
|
return NULL;
|
||||||
|
|
||||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||||
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
|
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
|
||||||
@@ -187,60 +180,10 @@ xtext_surface_from_pixbuf (GdkPixbuf *pixbuf)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
src_stride = gdk_pixbuf_get_rowstride (pixbuf);
|
cr = cairo_create (surface);
|
||||||
src_pixels = gdk_pixbuf_get_pixels (pixbuf);
|
gdk_cairo_set_source_window (cr, window, 0.0, 0.0);
|
||||||
dest_stride = cairo_image_surface_get_stride (surface);
|
cairo_paint (cr);
|
||||||
dest_pixels = cairo_image_surface_get_data (surface);
|
cairo_destroy (cr);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user