aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2016-03-24 16:46:28 -0700
committerPaul Eggert2016-03-24 16:53:23 -0700
commit45577d548d3abfe504d3f936b3c9b997d0cf7f9c (patch)
tree58ef10604d72495109b310c94f319a9c9ac889c7
parente99ff6e85ae30d94150e5c67dff2dd81077a6692 (diff)
downloademacs-45577d548d3abfe504d3f936b3c9b997d0cf7f9c.tar.gz
emacs-45577d548d3abfe504d3f936b3c9b997d0cf7f9c.zip
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.
-rw-r--r--src/gtkutil.c100
1 files changed, 34 insertions, 66 deletions
diff --git a/src/gtkutil.c b/src/gtkutil.c
index ba059b73a70..e791e6ac317 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -252,35 +252,6 @@ xg_create_default_cursor (Display *dpy)
252 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR); 252 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
253} 253}
254 254
255static GdkPixbuf *
256xg_get_pixbuf_from_pixmap (struct frame *f, Pixmap pix)
257{
258 int iunused;
259 GdkPixbuf *tmp_buf;
260 Window wunused;
261 unsigned int width, height, uunused;
262 XImage *xim;
263
264 XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
265 &width, &height, &uunused, &uunused);
266
267 xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
268 ~0, XYPixmap);
269 if (!xim) return 0;
270
271 tmp_buf = gdk_pixbuf_new_from_data ((guchar *) xim->data,
272 GDK_COLORSPACE_RGB,
273 FALSE,
274 xim->bitmap_unit,
275 width,
276 height,
277 xim->bytes_per_line,
278 NULL,
279 NULL);
280 XDestroyImage (xim);
281 return tmp_buf;
282}
283
284/* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */ 255/* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
285 256
286static GdkPixbuf * 257static GdkPixbuf *
@@ -288,46 +259,43 @@ xg_get_pixbuf_from_pix_and_mask (struct frame *f,
288 Pixmap pix, 259 Pixmap pix,
289 Pixmap mask) 260 Pixmap mask)
290{ 261{
291 int width, height; 262 GdkPixbuf *icon_buf = 0;
292 GdkPixbuf *icon_buf, *tmp_buf; 263 int iunused;
293 264 Window wunused;
294 tmp_buf = xg_get_pixbuf_from_pixmap (f, pix); 265 unsigned int width, height, depth, uunused;
295 icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
296 g_object_unref (G_OBJECT (tmp_buf));
297
298 width = gdk_pixbuf_get_width (icon_buf);
299 height = gdk_pixbuf_get_height (icon_buf);
300 266
301 if (mask) 267 if (FRAME_DISPLAY_INFO (f)->red_bits != 8)
268 return 0;
269 XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
270 &width, &height, &uunused, &depth);
271 if (depth != 24)
272 return 0;
273 XImage *xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
274 ~0, XYPixmap);
275 if (xim)
302 { 276 {
303 GdkPixbuf *mask_buf = xg_get_pixbuf_from_pixmap (f, mask); 277 XImage *xmm = (! mask ? 0
304 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf); 278 : XGetImage (FRAME_X_DISPLAY (f), mask, 0, 0,
305 guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf); 279 width, height, ~0, XYPixmap));
306 int rowstride = gdk_pixbuf_get_rowstride (icon_buf); 280 icon_buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
307 int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf); 281 if (icon_buf)
308 int y; 282 {
309 283 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
310 for (y = 0; y < height; ++y) 284 int rowjunkwidth = gdk_pixbuf_get_rowstride (icon_buf) - width * 4;
311 { 285 for (int y = 0; y < height; y++, pixels += rowjunkwidth)
312 guchar *iconptr, *maskptr; 286 for (int x = 0; x < width; x++)
313 int x; 287 {
314 288 unsigned long rgb = XGetPixel (xim, x, y);
315 iconptr = pixels + y * rowstride; 289 *pixels++ = (rgb >> 16) & 255;
316 maskptr = mask_pixels + y * mask_rowstride; 290 *pixels++ = (rgb >> 8) & 255;
317 291 *pixels++ = rgb & 255;
318 for (x = 0; x < width; ++x) 292 *pixels++ = xmm && !XGetPixel (xmm, x, y) ? 0 : 255;
319 { 293 }
320 /* In a bitmap, RGB is either 255/255/255 or 0/0/0. Checking 294 }
321 just R is sufficient. */
322 if (maskptr[0] == 0)
323 iconptr[3] = 0; /* 0, 1, 2 is R, G, B. 3 is alpha. */
324
325 iconptr += rowstride/width;
326 maskptr += mask_rowstride/width;
327 }
328 }
329 295
330 g_object_unref (G_OBJECT (mask_buf)); 296 if (xmm)
297 XDestroyImage (xmm);
298 XDestroyImage (xim);
331 } 299 }
332 300
333 return icon_buf; 301 return icon_buf;