iconcache: Fix the icon of Kerbel Space Program

Kerbel Space Program, and perhaps some other SDL-based programs, use
a really dumb way of specifying icons, which is totally
non-standards-compliant.

The ICCCM specifies that the icon_pixmap field of WM_HINTS should be a
1-bit-deep Pixmap, but we've seen applications set it to a pixmap of the
root depth as well, so we support that.

Kerbel Space Program seems to use it with a 32-bit depth Pixmap,
signifying ARGB32 (which it is), along with a 1-bit icon_mask, which
crashes us.

Keep in mind that Pixmaps, by definition, have no Visual attached, so
we simply have to make a guess at the correct visual based on the
depth. Do that by assuming that a depth-32 visual always means ARGB32,
which is a pretty safe bet.
This commit is contained in:
Jasper St. Pierre 2015-02-17 23:37:01 -08:00
parent 7966f00a18
commit 9b903e93e3

View File

@ -27,8 +27,10 @@
#include <cairo.h>
#include <cairo-xlib.h>
#include <cairo-xlib-xrender.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
static gboolean
find_largest_sizes (gulong *data,
@ -284,34 +286,42 @@ get_pixmap_geometry (MetaDisplay *display,
*d = depth;
}
static int
standard_pict_format_for_depth (int depth)
{
switch (depth)
{
case 1:
return PictStandardA1;
case 24:
return PictStandardRGB24;
case 32:
return PictStandardARGB32;
default:
g_assert_not_reached ();
}
}
static XRenderPictFormat *
pict_format_for_depth (Display *xdisplay, int depth)
{
return XRenderFindStandardFormat (xdisplay, standard_pict_format_for_depth (depth));
}
static cairo_surface_t *
surface_from_pixmap (Display *xdisplay, Pixmap xpixmap,
int width, int height)
{
cairo_surface_t *surface;
Window root_return;
int x_ret, y_ret;
unsigned int w_ret, h_ret, bw_ret, depth_ret;
XWindowAttributes attrs;
if (!XGetGeometry (xdisplay, xpixmap, &root_return,
&x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
return NULL;
if (depth_ret == 1)
{
surface = cairo_xlib_surface_create_for_bitmap (xdisplay, xpixmap, DefaultScreenOfDisplay (xdisplay),
w_ret, h_ret);
}
else
{
if (!XGetWindowAttributes (xdisplay, root_return, &attrs))
return NULL;
surface = cairo_xlib_surface_create (xdisplay, xpixmap, attrs.visual, w_ret, h_ret);
}
return surface;
return cairo_xlib_surface_create_with_xrender_format (xdisplay, xpixmap, DefaultScreenOfDisplay (xdisplay),
pict_format_for_depth (xdisplay, depth_ret), w_ret, h_ret);
}
static gboolean