From f7e3d992c9b2afcf2896adc9dfb91ef2e3c2914d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 5 Oct 2012 22:41:02 -0400 Subject: [PATCH] Try to use _NET_WM_ICON if possible for X11's SDL_WM_SetIcon() implementation. This lets us have larger icons with more colors. --- src/video/x11/SDL_x11wm.c | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/video/x11/SDL_x11wm.c b/src/video/x11/SDL_x11wm.c index 14c816b94..cb77a78f7 100644 --- a/src/video/x11/SDL_x11wm.c +++ b/src/video/x11/SDL_x11wm.c @@ -43,6 +43,7 @@ static Uint8 reverse_byte(Uint8 x) void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask) { + Atom _NET_WM_ICON = XInternAtom(SDL_Display, "_NET_WM_ICON", False); SDL_Surface *sicon; XWMHints *wmhints; XImage *icon_image; @@ -60,6 +61,80 @@ void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask) SDL_Lock_EventThread(); + if (_NET_WM_ICON) { /* better interface for modern systems. */ + SDL_PixelFormat format; + SDL_Surface *surface; + int propsize; + long *propdata; + + /* Convert the icon to ARGB for modern window managers */ + SDL_memset(&format, 0, sizeof (format)); + format.BitsPerPixel = 32; + format.BytesPerPixel = 4; + #if SDL_BYTEORDER == SDL_BIG_ENDIAN + format.Rshift = 8; + format.Gshift = 16; + format.Bshift = 24; + format.Ashift = 0; + #else + format.Rshift = 16; + format.Gshift = 8; + format.Bshift = 0; + format.Ashift = 24; + #endif + format.Rmask = 0xFF << format.Rshift; + format.Gmask = 0xFF << format.Gshift; + format.Bmask = 0xFF << format.Bshift; + format.Amask = 0xFF << format.Ashift; + format.alpha = SDL_ALPHA_OPAQUE; + + surface = SDL_ConvertSurface(icon, &format, 0); + if (!surface) { + return; + } + + /* Set the _NET_WM_ICON property */ + propsize = 2 + (icon->w * icon->h); + propdata = SDL_malloc(propsize * sizeof(long)); + if (propdata) { + const Uint32 alpha = format.Amask; + int x, y; + Uint32 *src; + long *dst; + + propdata[0] = icon->w; + propdata[1] = icon->h; + dst = &propdata[2]; + + size_t maskidx = 0; + for (y = 0; y < icon->h; ++y) { + src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch); + for (x = 0; x < icon->w; ++x) { + const Uint32 pixel = *(src++); + if (mask[maskidx / 8] & (1<<(7-(maskidx % 8)))) { + *dst++ = pixel | alpha; + } else { + *dst++ = pixel & ~alpha; + } + maskidx++; + } + } + + XChangeProperty(SDL_Display, WMwindow, _NET_WM_ICON, XA_CARDINAL, + 32, PropModeReplace, (unsigned char *) propdata, + propsize); + } + + SDL_FreeSurface(surface); + SDL_free(propdata); + + SDL_Unlock_EventThread(); + + return; + } + + /* Do it the old way... */ + /* The icon must use the default visual, depth and colormap of the screen, so it might need a conversion */ dvis = DefaultVisual(SDL_Display, SDL_Screen);