Avoid GTK 3 crash with icons and masks
Problem reported by Mosè Giordano (Bug#18997). * src/gtkutil.c (xg_get_pixbuf_from_pixmap): Remove. (xg_get_pixbuf_from_pix_and_mask): Do not use xg_get_pixbuf_from_pixmap, as it is poorly documented. Instead, invoke XGetPixel directly. This is slow but speed is not important here. Also, fail for unusual situations (not TrueColor, or images that are not 8 bits per sample) instead of displaying junk or crashing.
This commit is contained in:
parent
e99ff6e85a
commit
45577d548d
1 changed files with 34 additions and 66 deletions
100
src/gtkutil.c
100
src/gtkutil.c
|
@ -252,35 +252,6 @@ xg_create_default_cursor (Display *dpy)
|
||||||
return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
|
return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkPixbuf *
|
|
||||||
xg_get_pixbuf_from_pixmap (struct frame *f, Pixmap pix)
|
|
||||||
{
|
|
||||||
int iunused;
|
|
||||||
GdkPixbuf *tmp_buf;
|
|
||||||
Window wunused;
|
|
||||||
unsigned int width, height, uunused;
|
|
||||||
XImage *xim;
|
|
||||||
|
|
||||||
XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
|
|
||||||
&width, &height, &uunused, &uunused);
|
|
||||||
|
|
||||||
xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
|
|
||||||
~0, XYPixmap);
|
|
||||||
if (!xim) return 0;
|
|
||||||
|
|
||||||
tmp_buf = gdk_pixbuf_new_from_data ((guchar *) xim->data,
|
|
||||||
GDK_COLORSPACE_RGB,
|
|
||||||
FALSE,
|
|
||||||
xim->bitmap_unit,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
xim->bytes_per_line,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
XDestroyImage (xim);
|
|
||||||
return tmp_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
|
/* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
|
||||||
|
|
||||||
static GdkPixbuf *
|
static GdkPixbuf *
|
||||||
|
@ -288,46 +259,43 @@ xg_get_pixbuf_from_pix_and_mask (struct frame *f,
|
||||||
Pixmap pix,
|
Pixmap pix,
|
||||||
Pixmap mask)
|
Pixmap mask)
|
||||||
{
|
{
|
||||||
int width, height;
|
GdkPixbuf *icon_buf = 0;
|
||||||
GdkPixbuf *icon_buf, *tmp_buf;
|
int iunused;
|
||||||
|
Window wunused;
|
||||||
|
unsigned int width, height, depth, uunused;
|
||||||
|
|
||||||
tmp_buf = xg_get_pixbuf_from_pixmap (f, pix);
|
if (FRAME_DISPLAY_INFO (f)->red_bits != 8)
|
||||||
icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
|
return 0;
|
||||||
g_object_unref (G_OBJECT (tmp_buf));
|
XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
|
||||||
|
&width, &height, &uunused, &depth);
|
||||||
width = gdk_pixbuf_get_width (icon_buf);
|
if (depth != 24)
|
||||||
height = gdk_pixbuf_get_height (icon_buf);
|
return 0;
|
||||||
|
XImage *xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
|
||||||
if (mask)
|
~0, XYPixmap);
|
||||||
|
if (xim)
|
||||||
{
|
{
|
||||||
GdkPixbuf *mask_buf = xg_get_pixbuf_from_pixmap (f, mask);
|
XImage *xmm = (! mask ? 0
|
||||||
guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
|
: XGetImage (FRAME_X_DISPLAY (f), mask, 0, 0,
|
||||||
guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf);
|
width, height, ~0, XYPixmap));
|
||||||
int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
|
icon_buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
|
||||||
int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf);
|
if (icon_buf)
|
||||||
int y;
|
{
|
||||||
|
guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
|
||||||
|
int rowjunkwidth = gdk_pixbuf_get_rowstride (icon_buf) - width * 4;
|
||||||
|
for (int y = 0; y < height; y++, pixels += rowjunkwidth)
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
unsigned long rgb = XGetPixel (xim, x, y);
|
||||||
|
*pixels++ = (rgb >> 16) & 255;
|
||||||
|
*pixels++ = (rgb >> 8) & 255;
|
||||||
|
*pixels++ = rgb & 255;
|
||||||
|
*pixels++ = xmm && !XGetPixel (xmm, x, y) ? 0 : 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (y = 0; y < height; ++y)
|
if (xmm)
|
||||||
{
|
XDestroyImage (xmm);
|
||||||
guchar *iconptr, *maskptr;
|
XDestroyImage (xim);
|
||||||
int x;
|
|
||||||
|
|
||||||
iconptr = pixels + y * rowstride;
|
|
||||||
maskptr = mask_pixels + y * mask_rowstride;
|
|
||||||
|
|
||||||
for (x = 0; x < width; ++x)
|
|
||||||
{
|
|
||||||
/* In a bitmap, RGB is either 255/255/255 or 0/0/0. Checking
|
|
||||||
just R is sufficient. */
|
|
||||||
if (maskptr[0] == 0)
|
|
||||||
iconptr[3] = 0; /* 0, 1, 2 is R, G, B. 3 is alpha. */
|
|
||||||
|
|
||||||
iconptr += rowstride/width;
|
|
||||||
maskptr += mask_rowstride/width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref (G_OBJECT (mask_buf));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return icon_buf;
|
return icon_buf;
|
||||||
|
|
Loading…
Add table
Reference in a new issue